27

The more functional programming I do, the more I feel like it adds an extra layer of abstraction that seems like how an onion's layer is- all encompassing of the previous layers.

I don't know if this is true so going off the OOP principles I've worked with for years, can anyone explain how functional does or doesn't accurately depict any of them: Encapsulation, Abstraction, Inheritance, Polymorphism

I think we can all say, yes it has encapsulation via tuples, or do tuples count technically as fact of "functional programming" or are they just a utility of the language?

I know Haskell can meet the "interfaces" requirement, but again not certain if it's method is a fact of functional? I'm guessing that the fact that functors have a mathematical basis you could say those are a definite built in expectation of functional, perhaps?

Please, detail how you think functional does or does not fulfill the 4 principles of OOP.

Edit: I understand the differences between the functional paradigm and object oriented paradigm just fine and realize there are plenty of multiparadigm languages these days which can do both. I am really just looking for definitions of how outright fp (think purist, like haskell) can do any of the 4 things listed, or why it cannot do any of them. i.e. "Encapsulation can be done with closures" (or if I am wrong in this belief, please state why).

10
  • 7
    Those 4 principles don't "make" OOP. OOP simply "solves" those by use of classes, class hiearchy and their instances. But I too would like an answer if there are ways to achieve those in functional programming.
    – Euphoric
    Sep 3, 2012 at 6:05
  • 3
    @Euphoric Depending on the definition, it does make OOP. Sep 3, 2012 at 12:24
  • 2
    @KonradRudolph I know a lot of people claim these things and the benefits they bring as unique properties of OOP. Assuming "polymorphism" means "subtype polymorphism", I can go with the latter two being integral to OOP. But I have yet to encounter a useful definition of encapsulation and abstraction that excludes decidedly non-OOP approaches. You can hide details and limit access to them just fine even in Haskell. And the Haskell also has ad-hoc polymorphism, just not subtype polymorphism -- the question is, does the "subtype" bit matter?
    – user7043
    Sep 3, 2012 at 16:24
  • 1
    @KonradRudolph That does not make it any more acceptable. If anything, it's incentive to step up and giving those spreading it reason to re-consider it.
    – user7043
    Sep 3, 2012 at 16:35
  • 1
    Abstraction is Intrinsic to any programming, at least any programming beyond raw machine code. Encapsulation has been around long before OOP, and it is intrinsic to functional programming. A functional language is not required to include explicit syntax for either inheritance or polymorphism. I guess that adds up to 'no'.
    – sdenham
    May 18, 2016 at 21:19

6 Answers 6

47

Functional programming isn't a layer above OOP; it's a completely different paradigm. It's possible to do OOP in a functional style (F# was written for exactly this purpose), and on the other end of the spectrum you have stuff like Haskell, which explicitly rejects the principles of object orientation.

You can do encapsulation and abstraction in any language advanced enough to support modules and functions. OO provides special mechanisms for encapsulation, but it's not something inherent to OO. The point of OO is the second pair you mentioned: inheritance and polymorphism. The concept is formally known as Liskov substitution, and you can't get it without language-level support for object-oriented programming. (Yes, it's possible to fake it in some cases, but you lose a lot of the advantages that OO brings to the table.)

Functional programming doesn't focus on Liskov substitution. It focuses on increasing the level of abstraction, and on minimizing the use of mutable state and routines with "side effects", which is a term functional programmers like to use to make routines that actually do something (as opposed to simply calculating something) sound scary. But again, they're completely separate paradigms, that can be used together, or not, depending on the language and the skill of the programmer.

6
  • 1
    Well, inheritance (in those exceptionally rare cases when it is needed) is achievable over composition, and it is cleaner than the type-level inheritance. Polymorphism is natural, especially in presence of polymorphic types. But of course I agree that FP has nothing to do with OOP and its principles.
    – SK-logic
    Sep 3, 2012 at 7:15
  • It's always possible to fake it - you can implement objects in any language you choose. I agree with everything else though :)
    – Eliot Ball
    Sep 3, 2012 at 9:33
  • 5
    I don't think the term "side effects" was coined (or is primarily used) by functional programmers.
    – sepp2k
    Sep 3, 2012 at 11:21
  • 4
    @sepp2k: He didn't say that they invented the term, just that they wield it using roughly the same tone as one would normally use to refer to kids who refuse to get off of their lawn.
    – Aaronaught
    Sep 3, 2012 at 12:57
  • 18
    @Aaronaught it's not the kids on my lawn that bother me, it's their bloody side effects! If they would just stop mutating all over my lawn I wouldn't mind them at all. Sep 3, 2012 at 18:17
10

I find the following intuition useful to compare OOP and FP.

Rather than considering FP as a superset of OOP, think of OOP and FP as two alternative ways of looking at a similar underlying computation model in which you have:

  1. Some operation that is executed,
  2. some input arguments to the operation,
  3. some fixed data / parameters that can influence the definition of the operation,
  4. some result value, and
  5. possibly a side-effect.

In OOP this is captured by

  1. A method that is executed,
  2. the input arguments of a method,
  3. the object on which the method is invoked, containing some local data in the form of member variables,
  4. the method's return value (possibly void),
  5. the method's side-effects.

In FP this is captured by

  1. A closure that is executed,
  2. the input arguments of the closure,
  3. the captured variables of the closure,
  4. the closure's return value,
  5. the closure's possible side effects (in pure languages like Haskell, this happens in a very controlled way).

With this interpretation, an object can be seen as a collection of closures (its methods) all capturing the same non-local variables (the object's member variables common to all closures in the collection). This view is also supported by the fact that in object-oriented languages closures are often modeled as objects with exactly one method.

I think the different points of view originate from the fact that the object-oriented view is centered on the objects (the data) while the functional view is centered on the functions / closures (the operations).

8

It depends on who you ask for a definition of OOP. Ask five people and you’ll likely get six definitions. Wikipedia says:

Attempts to find a consensus definition or theory behind objects have not proven very successful

So whenever somebody gives a very definitive answer, take it with a grain of salt.

That said, there’s a good argument to be made that, yes, FP is a superset of OOP as a paradigm. In particular Alan Kay’s definition of the term object-oriented programming doesn’t contradict this notion (but Kristen Nygaard’s does). All Kay was really concerned with was that everything is an object, and that logic is implemented by passing messages between object.

Maybe more interestingly for your question, classes and objects can be thought of in terms of functions and closures returned by functions (which act as classes and constructors at once). This comes very close to prototype-based programming, and in fact JavaScript allows doing precisely that.

var cls = function (x) {
    this.y = x;
    this.fun = function () { alert(this.y); };
    return this;
};

var inst = new cls(42);
inst.fun();

(Of course JavaScript allow mutating values which is illegal in purely functional programming but nor is it required in a strict definition of OOP.)

The more important question though is: Is this a meaningful classification of OOP? Is it helpful of thinking of it as a subset of functional programming? I think that in most cases, it isn’t.

1
  • 1
    I feel it may be meaningful in thinking through where the line should be drawn on when I switch paradigms. If it's said there is no way to achieve subtypal polymorphism in fp, then I won't bother ever trying to use fp in modeling something that would fit well with it. If however it's possible, I may take the time to achieve a good way of doing it (though a good way may not be possible) when working heavily in an fp space but wanting subtypal polymorphism in a few niche spaces. Obviously if the majority of the system fits with it however, than it would be better to use OOP. Sep 3, 2012 at 18:52
6

FP like OO isn't a well defined term. There are schools with different, sometimes conflicting, definitions. If you take what they have in common, you get down to:

  • functional programming is programming with first class functions

  • OO programming is programming with inclusion polymorphism combined with at least a restricted form of dynamically resolved overloading. (A side note: in OO circles polymorphism is usually taken to mean inclusion polymorphism, while FP schools it usually means parametric polymorphism.)

Everything else is either present elsewhere, or absent in some cases.

FP and OO are two abstractions building tool. They each have their own strengths and weaknesses (for instance they have a different preferred extension direction in the expression problem), but none is intrinsically more powerful than the other. You can build an OO system over a FP kernel (CLOS is one such system). You can use an OO framework to get first class functions (see the way lambda functions are defined in C++11 for instance).

3
  • I think you mean 'first class functions' rather than 'first order functions'. Sep 3, 2012 at 19:28
  • Errr... C++11 lambdas are hardly first-class functions: Each lambda has its own ad-hoc type (for all practical purposes, an anonymous struct), incompatible with a native function pointer type. And std::function, to which both function pointers and lambdas can be assigned, is decidedly generic, not object-oriented. This is no surprise, because object-orientation's limited brand of polymorphism (subtype polymorphism) is strictly less powerful than parametric polymorphism (even Hindley-Milner, let alone full System F-omega).
    – isekaijin
    Sep 8, 2013 at 3:43
  • I don't have a ton of experience with purist functional languages but if you can define one-static-method classes within closures and pass them around to different contexts, I'd say you're (awkwardly perhaps) at least half-way there on functional-style options. There's a lot of ways to work around strict params in most languages. Nov 15, 2013 at 16:41
2

No; OOP may be seen as a superset of procedural programming and differs fundamentally from functional paradigm because it has state represented in the instance fields. In functional paradigm the variables are functions which are applied on the constant data in order to obtain the desired result.

Actually you can consider functional programming a subset of OOP; if you make all of your classes immutable you may consider you have some kind of functional programming.

6
  • 3
    Immutable classes does not make higher order functions, list comprehensions, or closures. Fp is not a subset. Sep 3, 2012 at 14:14
  • 1
    @Jimmy Hoffa: You can easily simulate a higher oreder function by creating a class which has a single method which takes on or more objects of a similar type and also returns an object of this similar type (type which has a method and no fields). List comperhension is not something related to programming language not paradigm (Smalltalk supports it and is OOP). Closures are present in C# and will be inserted in Java too.
    – Random42
    Sep 3, 2012 at 17:07
  • yes C# has closures, but that is because it is multi-paradigm, closures were added along with other fp pieces to C# (for which I am eternally grateful) but their presence in an oop language doesn't make them oop. Good point about the higher order function though, encapsulation of a method in a class does allow the same behavior. Sep 3, 2012 at 18:21
  • 2
    Yeah, but if use use closures to alter state, would you still program in a functional paradigm? The point is - functional paradigm is about lack of state not about high-order functions, recursion or closures.
    – Random42
    Sep 3, 2012 at 18:56
  • interesting thought on the definition of fp.. I'll have to think more about this, thanks for sharing your observations. Sep 3, 2012 at 19:00
2

Answer:

Wikipedia has a great article on Functional Programming with some of the examples you ask for. @Konrad Rudolph already provided the link to the OOP article.

I don't think one paradigm is a super-set of the other. They are different perspectives on programming and some problems are better solved from one perspective and some from another.

Your question is further complicated by all the implementations of FP and OOP. Each language has its own quirks that are relevant to any good answer to your question.

Increasingly Tangential Rambling:

I like the idea that a language like Scala tries to give you the best of both worlds. I worry that it gives you the complications of both worlds as well.

Java is an OO language, but version 7 added a "try-with-resources" feature which can be used to imitate a kind of closure. Here it imitates updating a local variable "a" in the middle of another function, without making it visible to that function. In this case the first half of the other function is the ClosureTry() constructor and the second half is the close() method.

public class ClosureTry implements AutoCloseable {

    public static void main(String[] args) {
        int a = 1;
        try(ClosureTry ct = new ClosureTry()) {
            System.out.println("Middle Stuff...");
            a = 2;
        }
        System.out.println("a: " + a);
    }

    public ClosureTry() {
        System.out.println("Start Stuff Goes Here...");
    }

    /** Interface throws exception, but we don't have to. */
    public void close() {
        System.out.println("End Stuff Goes Here...");
    }
}

Output:

Start Stuff Goes Here...
Middle Stuff...
End Stuff Goes Here...
a: 2

This is could be useful for its intended purpose of opening a stream, writing to the stream, and closing it reliably, or for simply pairing two functions in a way that you don't forget to call the second one after doing some work between them. Of course, it's so new and unusual that another programmer might remove the try block without realizing they are breaking something, so it's currently kind of an anti-pattern, but interesting that it can be done.

You can express any loop in most imperative languages as a recursion. Objects and variables can be made immutable. Procecures can be written to minimize side effects (though I would argue that a true function is not possible on a computer - the time it takes to execute and the processor/disk/system resources it consumes are unavoidable side effects). Some functional languages can be made to do many if not all object-oriented operations as well. They don't have to be mutually exclusive, though some languages have limitations (like not allowing any updating of variables) that prevent certain patterns (like mutable fields).

To me, the most useful parts of object oriented programming are data hiding (encapsulation), treating similar-enough objects as the same (polymorphism), and collecting your data and methods that operate on that data together (objects/classes). Inheritance may be the flagship of OOP, but to me it is the least important and least used part.

The most useful parts of functional programming are immutability (tokens/values instead of variables), functions (no side effects), and closures.

I don't think it's object-oriented, but I have to say that one of the most useful things in computer science is the ability to declare an interface, then have various pieces of functionality and data implement that interface. I also like to have a few mutable pieces of data to work with, so I guess I'm not totally comfortable in exclusively functional languages, even though I try to limit mutability and side effects in all my program designs.

Not the answer you're looking for? Browse other questions tagged or ask your own question.