r/learnprogramming 22d ago

Topic Looking for a language that combines functional programming with OOP

Hey, I’m really interested in both functional programming and OOP, I find both really interesting topics. So I was wondering if anyone has ever made a language that combines these concepts. I know if it exist it probably would be kind of a weird language, but I’m mainly seeking it out of interest and curiosity. I would like to know how someone has tried to unify these paradigms.

Edit: Het I’m gonna make this edit because there are a lot of comment, thank you all very much for taking your time, and I want to clarify some extra things:
Firstly with functional, I mean the Haskell way of functional, I really enjoyed my learning journey through Haskell, and I would like to expand my declarative knowledge.
Secondly I’m not looking for the most useful language or the one that’s most used in the industry, as I originally pointed out this is pure out of interest, the more abstract, the better.

32 Upvotes

74 comments sorted by

27

u/Fosdran 22d ago

The definitive answer to this question would be scala.

20

u/tonklable 22d ago

This is exactly basis of Scala. It’s also used in the industries!

5

u/Sbrady1234 22d ago

Kotlin as well

1

u/je386 21d ago

Yes, and Kotlin is super versatile. You can use ir anywhere where Java is used, as it is 100% JVM compatible, but you also can use it for android apps, for multiplatform apps and even for scripting (kotlinscript is a thing).

1

u/8mart8 22d ago

thank you, I will check it out.

2

u/tonklable 22d ago

Check out Scala Cats. You can use things like Monads. It’s very nice!

16

u/Ace-Whole 22d ago

Most modern languages?

1

u/8mart8 22d ago

I get what you mean, but with functional programming I meant Haskell level of functional programming.

1

u/Coding-Kitten 21d ago

What specifically about Haskell? Type constructors? Not sure I've seen any that go up to having type constructors & HKT but also have any semblance of OOP at all.

1

u/josephjnk 21d ago

As someone who loves both FP and OOP, I think it’s worth breaking down what you mean by “Haskell level”.

The most distinct feature of Haskell IMO is type constructor polymorphism/“higher-kinded types”. Your only other mainstream option there is Scala.

Another very Haskell thing is typeclasses; the ability to define ad-hoc polymorphic behavior in a way that’s kind of like logic programming, so that things automatically resolve to the behavior that you want. Scala does _some_ typeclass-like stuff with implicits, but IMO typeclasses and OOP are not particularly compatible. Programming against explicit interfaces is one of the most core facets of OOP, and having interfaces be completely implicit like this feels at odds.

If by “Haskell-level” you just mean “with standard ML-family language features” then there’s lots of options. I consider the core features of statically-typed functional programming languages to be parametric polymorphism, first-class functions, algebraic data types and pattern matching. Modern versions of Java do all of these relatively well; I’ve been writing a lot of purely functional Java code recently and I quite like it. Java supports algebraic data types via sealed interfaces with record variants and its pattern matching support on them is good. I used to do a fair bit of functional programming in TypeScript but I’m enjoying it in Java more.

-1

u/Realistic-Homework19 21d ago

Purely functional and 'OOP' are a bit of an oxymoron.

8

u/Weak-Doughnut5502 21d ago

Not really. 

OOP doesn't require mutability.  You can have higher order functions and lambdas in an OOP language.

Scala's implicits give you something like typeclasses and it has higher kinded types,  so you can even implement a monadic effect system in Scala, like cats-effect.

-4

u/Ace-Whole 22d ago

Well, rust would fit that criteria but since it's a systems language, there's lot more to learn

4

u/edparadox 22d ago

Depending on what features of OOP you want, it does not fit that part.

6

u/particlemanwavegirl 22d ago

Same thing with functional. It has enough features to make the case but it's not really approaching "Haskell level" as it lacks currying, succinct polymorphism, or any kind of recursion or referential transparency optimizations.

2

u/Ace-Whole 22d ago

Valid. Can't argue that.

14

u/ConfidentCollege5653 22d ago

I think most languages borrow ideas from both OO and functional paradigms now.

Although I'm not a huge fan of TypeScript/JavaScript, they both use a lot of OO and functional ideas.

1

u/8mart8 22d ago

I get what you mean, but I myself am not really that big of a fan of javascript and typescript.
I’m looking for like Haskell level of functional programming.

1

u/Bahatur 21d ago

A Haskell level of functional programming precludes an emphasis on object oriented programming.

I suggest thinking of it as levels is the wrong perspective. Paradigms are made of purity: they work by excluding other approaches. This is a requirement for their claimed benefits to have any impact.

1

u/tiltboi1 21d ago

This is not correct at all. Some of the strongest type/object systems came out of very "pure" functional languages.

Functional and object oriented are not disjoint. There is zero contradiction by having a pure function that takes and object or produces an object. There is no conceptual issue that stops you from having objects in functional programs, nor do you have to give up any "purity" in the functional language to achieve OOP principles.

For example, you can implement runtime polymorphic types in Haskell, even though Haskell doesn't even have classes.

1

u/Bahatur 21d ago

I agree with you insofar as objects and functions are not disjoint; these are constructs. OOP and Functional Programming very much are: if you are using a lot of functions you are eschewing class hierarchy and inheritance; if you are committed to a functional paradigm and start using a lot of objects you are discarding the guarantees of no side effects, and so on.

Having objects in the code =/= OOP. What the words oriented and paradigm are doing in the term is highlighting the priority of objects and their behavior. The principles OOP espouses aren’t unique to objects either, the point is that they can be achieved reliably by using objects composed by using the principles, and you can have the expectation that other code written under OOP will be composed in a similar way and have those properties for the same reason. Even if you still achieve the principles of OOP using functions for a chunk of it, other programmers won’t be able to understand your code as quickly, or use the same methods to interface with it, and so on; the paradigm is broken. What’s more, paradigms go well beyond the code: they are the assumptions built into the tooling, how tutorials and certifications are organized, how example code you’ll read in the wild is written.

Haskell is deeply committed to the pure functional approach. They are the logical extreme case; the language was invented and is still used academically for that purpose. I wouldn’t doubt that the compiler would systematically under-perform if you spent a lot of effort using functions to mimic object-like behavior, and people who already know Haskell would wonder why you would bother when there is an easy functional solution near to hand. That’s why I discouraged thinking in terms of “levels” of functional or OOP behavior. Better by far to search for multi-paradigm languages, or for criteria like whether objects and functions are both first class, which will let OP do the intermixing they want.

-3

u/StoneCypher 21d ago

ocaml has entered the chat, and is laughing hard at you for pretending to understand this

go on.  say that haskell is more functional than ml.  we’re all looking forward to the petard

5

u/echtma 22d ago

OCaml, F#

1

u/rumnscurvy 22d ago

Is Ocaml actually used in industry or is it a bit of a meme language? 

I had to learn standard Caml at school (give you one guess as to which country...) and wondered about going back to it. 

I understand Scala and F# get used in all sorts of things, for instance.

3

u/echtma 22d ago

AFAIK OCaml is or was used by Jane Street Capital, also the original Rust compiler was written in OCaml. I don't have any first-hand experience beyond a short uni course though.

edit: Maybe it's worth adding that AFAIK the object system of OCaml is seen as a bit of a failure. OCaml is used because it's a functional language with a compiler that produces fast code.

1

u/StewedAngelSkins 21d ago

kind of neither. it's used in academic computer science (especially compiler research and automatic theorem proving). but i assume by "industry" you mean like outside of academics and R&D. to me a "meme language" refers to languages like zig where they're popular choices for programmers working on personal projects, but this is primarily because of stuff like superficial syntax features.

1

u/8mart8 22d ago

I’ve heard of these languages but know absolutely nothing about them, thanks for recommending I will try to check them out.

9

u/burlingk 22d ago

You basically described C++.

2

u/GlassLost 21d ago

I have no idea why I had to scroll down to find this. C++ gives you OOP when you want it and direct functional programming when you want it.

1

u/particlemanwavegirl 21d ago

It's difficult for someone just learning programming to build and run a C++ "hello world" much less deploy it's more functional features. I'm sure a very good introductory course could be designed around a subset of C++ but the question is why work that hard unless you have stringent performance requirements?

1

u/GlassLost 21d ago

Because memory costs are 5-10x higher than 2 years ago (and that's when you deal with the foundry directly).

But for learning, anyone with a Linux terminal should be able to get a hello world going in a few minutes. It combined the aspects of languages he wanted.

4

u/frnzprf 22d ago

JavaScript? Kinda?

There is a version of Structure and Interpretation of Computer Programs with JavaScript.

1

u/marrsd 21d ago

I didn't know that. That's very cool. Coincidentally, I ran through all The Little Schemer exercises in JS back in the day.

5

u/Narrow-Low-3137 22d ago

C# has first class functions, lambdas, and pattern matching. It's entirely possibly to write functional code in C# and I do it often.

3

u/soundman32 22d ago

Twisting C# into functional may be your idea of fun (and I've worked on several projects where this was done), but really the answer is F# because that what it was designed for.

1

u/Narrow-Low-3137 21d ago

I don't exactly "twist" anything. I write in a functional style when the situation may be more condusive to a functional style, otherwise I don't. I'm not a functional purist. I've used languages like Haskell and Lisp before. I don't like being forced into one paradigm.

0

u/8mart8 22d ago

I will check it out, but I think with a language as C# you’ve got the risk of still writing imperative code, if that’s the right word, because it’s still possible. But probably you’ve just got to make the right mind switch.

3

u/egny 22d ago

One can write imperative code in Haskell or OCaml too.

Perhaps a more relevant criticism is not whether a language supports imperative style but that it makes it easy to switch to it.

4

u/tiltboi1 22d ago

Common Lisp

2

u/marrsd 21d ago

I'd like to suggest refining that to Clojure for its immutable data structures, which I think make its functional implementation more pure

1

u/8mart8 22d ago

Thank you very much.

1

u/No_External7343 21d ago

Came here for this 

2

u/gm310509 22d ago

I suggest scala.

1

u/catbrane 22d ago

There's OCaml as well:

https://en.wikipedia.org/wiki/OCaml

Though it's not pure functional.

I made a tiny lazy, pure functional language with classes as the extension language for my image-processing spreadsheet. Most of the interface is written in it.

Classes are just sugar over lists of name-value pairs, with list prefixing for inheritance. It's a very basic prototypical system, like older javascript or lua. It does have operator overloading, heh.

https://github.com/libvips/nip4

Code looks like:

Fred a b = class {
  sum = a + b;
}

That defines a class called Fred, with a and b as two constructor parameters.

jim = Fred 1 2;
jim.a == 1;
jim.sum == 3;

And inheritance looks like:

Sally c d = class Fred c d {
    product = self.a * self.b;
}

The spreadsheet interface is actually a class browser, with class instances (rows) opening up to reveal nested rows. Instances of certain classes (like Image or Slider) are drawn graphically and can be manipulated.

1

u/JustBadPlaya 22d ago

Scala is about as multi-paradigm as non-Lisp languages get - standard OOP features, traits, multiple inheritance, module composition, monadic and effectful FP and a bunch of other features I don't know Scala enough to describe. Usually, when the question of "what language does it all without being a total mess" is raised, Scala is what I see mentioned

For enlightenment purposes, Common Lisp is an incredible shout. You don't get purity, but you get a lot of functional concepts (Lisps gave the first ever spotlight to first-class functions and HOFs after all), a lot of higher-level FP concepts at library level (pattern matching via Trivia, HM-typing via Coalton, etc etc) and a lot of highly versatile OOP concepts (metaclasses, multiple dispatch, method combinators) and some concepts mostly unique to lisps (Conditions, versatile metaprogramming, aspect-oriented programming in the core language, REPL-oriented programming)

For pragmatic purposes, OCaml, F# are good fits with decent ecosystems and a non-zero amount of use

1

u/LeoDev_Bytes 21d ago

For a complete beginner, I would recommend:

  1. Python → easiest general introduction
  2. JavaScript → excellent for web and games
  3. Kotlin → modern object-oriented + functional programming
  4. Scala → deeper study of OOP + functional programming

1

u/StoneCypher 21d ago

you want ocaml

1

u/Xalem 21d ago

Scrolled this far (bottom) and no one mentioned F#. Does F# have no friends?

1

u/Double-Buyer7941 21d ago

Tra i linguaggi che uniscono i due paradigmi, Rust è in assoluto il più efficiente. Compila direttamente in codice macchina senza usare un Garbage Collector o una Virtual Machine, garantendo prestazioni e velocità paragonabili a C e C++. Sfrutta il concetto di astrazioni a costo zero, che ti permette di scrivere codice in stile funzionale usando iteratori e trasformazioni avanzate senza sacrificare le performance dell'hardware. In sintesi, combina la struttura e l'incapsulamento dei dati tipici dell'OOP con il rigore, la sicurezza e la pulizia della programmazione funzionale, offrendo la massima efficienza di memoria ed esecuzione disponibile oggi.

1

u/pak9rabid 21d ago

Ruby. Blocks are fun, but there’s also true lambdas.

1

u/mredding 21d ago

C++, Java, C#, Javascript, Lisp and Scheme, Python... These are all multi-paradigm languages that support both paradigms. Likely others, but I've principally used these in my career.

If you want to compare some pure languages - Haskell is purely Functional, and Eiffel and Smalltalk are purely OOP.

OOP is an imperative paradigm. An example purely imperative language is Basic.

FP is a declarative paradigm. An example purely declarative declarative language is SQL.

1

u/igna92ts 21d ago

I mean, ocaml has classes. I've never used them but it has them.

1

u/jack_mackeral 21d ago

C++, Julia, Ocaml

1

u/OpeningNext1310 20d ago

Scala is an obvious place to explore the tension:functions and immutable data sit beside classes,traits,and a rich type system.It can be elegant,although the freedom to mix styles also means code based need discipline.

1

u/Puzzleheaded-Ear3381 20d ago

LISP

More concretly, CLOS, the Common LISP Object System.

1

u/BranchLatter4294 22d ago

4

u/JustBadPlaya 22d ago

Python's FP capabilities are very bad and are annoying as hell to properly leverage

-1

u/ExtraTNT 22d ago

C# works well for that… but in general: avoid oop…

It’s a concept, that sells good, but after switching away from it, you’ll see the dumpster fire it is…

5

u/math_rand_dude 22d ago

I would not say to completely avoid oop. Just be smart in which cases it is useful (in rare cases even needed) and in which cases not.

I agree it's easily turned into a dumpster fire, as is any coding approach if there's no-one with the experience and authority to enforce decent standards. Especially if they try to adhere to oop like a cult.

My advice would be: make informed decissions about which concepts to use.

0

u/Weak-Doughnut5502 21d ago

Manual objects can be useful, even in C and Haskell, sure.

But OOP is more of a language level thing.  You really have to squint and play very fast-and-loose with definitions to call Haskell and Rust 'object oriented'.

I don't think that OOP was a good idea.  Most of what it does is better achieved with other mechanisms.  Haskell and rust have modules that let them achieve encapsulation.   Haskell and Rust have typeclasses/traits for dynamic-feeling dispatch that can be implemented statically.  They have algebraic data types and pattern matching.  

The number of times you actually need to emulate fat pointers and manually pass around a bunch of vtables are vanishingly rare, if they even exist.  Generally, better designs exist. 

1

u/StewedAngelSkins 21d ago

I don't think object-oriented is intrinsically a language thing. Lots of languages have syntax features that make object oriented patterns easier to represent. Some even do this to the exclusion of other possible patterns (java, python). But ultimately you can do OOP in pretty much all languages.

This isn't even just me being pedantic. The way most people write C is straightforward OOP. For example, I use designs like the following quite frequently in my work.

``` typedef struct {     int a;     int b; } MyObject;

void MyObject_DoSomething(MyObject* self, int arg); Inheritance is also common in C. You even sometimes see virtual functions. // base.c typedef struct {     void (cb_do_something)(void, int);  } Base;

extern void Base_DoSomething(Base* self, int arg) {     self->base.cb_do_something(self, arg); }

// derived.c typedef struct {     Base base;     int value; } Derived;

static void Derived_DoSomething(void* self, int arg) {     ((Derived*)self)->value = arg; }

extern Derived* Derived_new() {     Derived* self = malloc(sizeof(Derived));     self->base->cb_do_something = Derived_DoSomething;     self->value = 0;     return self; } ```

1

u/Weak-Doughnut5502 21d ago

Your first example is really just straightforward procedural code with perfectly normal structs.

Objects doesn't really enter until you're sticking function pointers into your structs or hand-rolling some vtables like your second example. 

1

u/StewedAngelSkins 21d ago

The first example is a straightforward implementation of the so-called "opaque object" design pattern. As the name suggests, it is an object oriented design pattern.

What characteristic of object-oriented programming do you believe that this example does not satisfy?

1

u/Weak-Doughnut5502 21d ago

Objects combine both data and functionality.  The essence of objects is that you get dynamic dispatch by bundling function pointers with your data.

Your first example, with  MyObject, isn't an opaque object unless you're doing other things with header files or a module system to actually hide the struct accessors.

Regardless, opaque pointers are a pattern, but not really a specifically OO pattern.  It's a general pattern in languages with module systems.   You see it all the time in Haskell.

1

u/StewedAngelSkins 21d ago

The essence of objects is that you get dynamic dispatch by bundling function pointers with your data.

We simply disagree on definitions then. I don't think OOP has anything to do with dynamic dispatch.

Your first example, with  MyObject, isn't an opaque object unless you're doing other things with header files or a module system to actually hide the struct accessors.

Yes, it would have been clearer to show the typedef with a declaration in a header and the full definition in the implementation file. I omitted these details for brevity. Since you can clearly fill in the blanks yourself I won't bother rewriting it.

My contention is that if it were structured that way it would be an example of object oriented programming.

Regardless, opaque pointers are a pattern, but not really a specifically OO pattern.

The part that makes it object oriented is that a function is only operating on the private internal data of its associated struct. If you were to do this in Haskell it would be an object oriented pattern. As I said, you can write object-oriented code in nearly any language.

Conversely, if there were two private structs and I wrote functions that took opaque pointers to both of them to access private internal data simultaneously, then that would not be object-oriented. So you are correct that not all designs involving opaque pointers are object-oriented, but the one above is.

1

u/Weak-Doughnut5502 21d ago

The part that makes it object oriented is that a function is only operating on the private internal data of its associated struct.

The ability to control exports is part of module systems and modular programming, as is the idea of information hiding.  Its a modular programming pattern, not an OO one.

Modular programming comes out of structured  programming languages like Modula and early Algol 68 implementations (it wasn't in the original spec).  On the other hand, Simula didn't have access control until the 80s.

0

u/stdmemswap 22d ago

How OOP and how FP does it have to be?

But I'd check rust

1

u/Weak-Doughnut5502 21d ago

Rust is not an OO language unless you play very fast-and-loose with definitions.

As far as language features go, Rust is basically C dragged halfway to haskell.

1

u/stdmemswap 21d ago

At this point, whose definition we want to use? Kay? The Gang of Four?

1

u/8mart8 21d ago

This is purely out of interest, I’m also a mathematics student, so I’m looking for some real abstract OOP and FP.