36

I have been interested in some of the concepts of functional programming lately. I have used OOP for some time now. I can see how I would build a fairly complex app in OOP. Each object would know how to do things that object does. Or anything it's parents class does as well. So I can simply tell Person().speak() to make the person talk.

But how do I do similar things in functional programming? I see how functions are first class items. But that function only does one specific thing. Would I simply have a say() method floating around and call it with an equivalent of Person() argument so I know what kind of thing is saying something?

So I can see the simple things, just how would I do the comparable of OOP and objects in functional programming, so I can modularize and organize my code base?

For reference, my primary experience with OOP is Python, PHP, and some C#. The languages that I am looking at that have functional features are Scala and Haskell. Though I am leaning towards Scala.

Basic Example (Python):

Animal(object):
    def say(self, what):
        print(what)

Dog(Animal):
    def say(self, what):
        super().say('dog barks: {0}'.format(what))

Cat(Animal):
    def say(self, what):
        super().say('cat meows: {0}'.format(what))

dog = Dog()
cat = Cat()
dog.say('ruff')
cat.say('purr')
14
  • Scala is designed as OOP + FP, so you dont have to choose
    – Karthik T
    Commented Dec 19, 2012 at 5:41
  • 1
    Yes I am aware, but i am also wanting to know for intellectual reasons. I cannot find anything on the equivalent of object in functional languages.As for scala, i would still want to know when/where/how i should use functional over oop, but that IMHO is another question.
    – skift
    Commented Dec 19, 2012 at 5:51
  • 2
    "Particularly over-emphasized, IMO is the notion that we don't maintain state.": This is the wrong notion. It is not true that FP does not use state, rather FP handles state in a different way (e.g. monads in Haskell or unique types in Clean).
    – Giorgio
    Commented Dec 19, 2012 at 7:05
  • 1
    possible duplicate of How to organize functional programs
    – Doc Brown
    Commented Dec 19, 2012 at 7:08
  • 3
    possible duplicate of Functional Programming vs. OOP
    – Caleb
    Commented Dec 19, 2012 at 9:00

7 Answers 7

22

What you are really asking about here is how to do Polymorphism in functional languages, i.e. how to create functions that behave differently based on their arguments.

Note the first argument to a function is typically equivalent to the "object" in OOP, but in functional languages you usually want to separate functions from data, so the "object" is likely to be a pure (immutable) data value.

Functional languages in general provide various options for achieving polymorphism:

  • Something like multimethods which call a different function based on examining the arguments provided. This can be done on the type of the first argument (which is effectively equal to the behaviour of most OOP languages), but could also be done on other attributes of the arguments.
  • Prototype / object-like data structures which contain first-class functions as members. So you could embed a "say" function inside your dog and cat data structures. Effectively you have made the code part of the data.
  • Pattern matching - where pattern matching logic is built into the function definition, and ensures different behaviours for different parameters. Common in Haskell.
  • Branching / conditions - equivalent to if / else clauses in OOP. Might not be highly extensible, but can still be appropriate in many cases when you have a limited set of possible values (e.g. was the function passed a number or a string or null?)

As an example, here's a Clojure implementation of your problem using multimethods:

;; define a multimethod, that dispatched on the ":type" keyword
(defmulti say :type)  

;; define specific methods for each possible value of :type. You can add more later
(defmethod say :cat [animal what] (println (str "Car purrs: " what)))
(defmethod say :dog [animal what] (println (str "Dog barks: " what)))
(defmethod say :default [animal what] (println (str "Unknown noise: " what)))

(say {:type :dog} "ruff")
=> Dog barks: ruff

(say {:type :ape} "ook")
=> Unknown noise: ook

Note that this behaviour doesn't require any explicit classes to be defined: regular maps work fine. The dispatch function (:type in this case) could be any arbitrary function of the arguments.

1
  • Not 100% clear, but enough to see where you are going. I could see this as the 'animal' code in a given file. Also the part on branching/conditions is good too. I had not considered that as the alternative to if/else.
    – skift
    Commented Dec 19, 2012 at 8:12
14

This is not a direct answer, nor is it necessarily 100% accurate as I'm not a functional language expert. But in either case, I'll share with you my experience...

About a year ago I was in a similar boat as you. I've done C++ and C# and all of my designs were always very heavy on OOP. I've heard about FP languages, read some info online, flipped through F# book but still couldn't really grasp how can an FP language replace OOP or be useful in general as most examples I've seen were just too simple.

For me the "breakthrough" came when I decided to learn python. I downloaded python, then went to project euler homepage and just started doing one problem after another. Python is not necessarily an FP language and you can certainly create classes in it, but compared to C++/Java/C#, it does have a lot more of FP constructs, so when I started playing with it, I made a conscious decision not to define a class unless I absolutely had to.

What I found interesting about Python was how easy and natural it was to take functions and "stitch" them to create more complex functions and in the end your problem was still solved by calling a single function.

You pointed out that when coding you should follow single responsibility principle and that is absolutely correct. But just because function is responsible for a single task, doesn't mean it can only do the absolute bare minimum. In FP, you still have abstraction levels. So your higher-level functions can still do "one" thing but they can delegate to lower level functions to implement finer details of how that "one" thing is achieved.

The key with FP however is that you do not have side-effects. As long as you treat the application as simple data transformation with defined set of inputs and set of outputs, you can write FP code that would accomplish what you need. Obviously not every application will fit nicely into this mold, but once you start doing it, you'll be surprised how many applications do fit. And this is where I think Python, F# or Scala shine because they give you FP constructs but when you do need to remember your state and "introduce side-effects" you can always fall back on true and tried OOP techniques.

Since then, I've written a whole bunch of python code as utilities and other helper scripts for internal work and some of them scaled out fairly far but by remembering basic SOLID principles, most of that code still came out very maintainable and flexible. Just like in OOP your interface is a class and you move classes around as you refactor and/or add functionality, in FP you do exactly same thing with functions.

Last week I started coding in Java and since then, almost on daily basis I get reminded that when in OOP, I have to implement interfaces by declaring classes with methods that override functions, in some cases I could achieve the same thing in Python using a simple lambda expression, for example, 20-30 lines of code that I wrote to scan a directory, would've been 1-2 lines in Python and no classes.

FP themselves are higher level languages. In Python (sorry, my only FP experience) I could put together list comprehension inside another list comprehension with lambdas and other stuff thrown in and the whole thing would only be 3-4 lines of code. In C++, I could absolutely accomplish the same thing, but because C++ is lower-level, I would have to write much more code than 3-4 lines and as the number of lines increases, my SRP training would kick in and I would start thinking about how to split up code into smaller pieces (i.e. more functions). But in the interests of maintainability and hiding implementation details, I would put all those functions into the same class and make them private. And there you have it... I just created a class whereas in python I would have written "return (.... lambda x:.. ....)"

4
  • Yes it doesnt directly answer the question, but still a great response. when i write smaller scripts or packages in python, i dont always use classes either. many times just having it in a package format fits perfectly. especially if i do not need state. I also agree that list comprehensions are damn useful as well. Since reading up on FP, i have realized how much more powerful they can be. which has then led me to wanting to learn more about FP, compared to OOP.
    – skift
    Commented Dec 19, 2012 at 8:02
  • Great answer. Speaks to everybody standing at the side of the funcctional pool but not sure whether to dip their toe in the water Commented Dec 25, 2012 at 22:31
  • And Ruby... One of its design philosophies centers on methods taking a code block as an argument, typically an optional one. And given the clean syntax thinking and coding this way is easy. It's hard to think and compose like this in C#. C# writ functionally is verbose and disorienting, it feels shoehorned into the language. I like that Ruby helped thinking functionally easier, to see potential in my staid C# thought box. In the final analysis i see functional and OO as complementary; I'd say Ruby certainly thinks so.
    – radarbob
    Commented Jun 8, 2017 at 0:02
  • I would add that one could even use classes and inheritance, as long as one treats the resulting objects as immutable. (E.g. once initialised, none of the methods should modify the object itself.)
    – oulenz
    Commented Dec 12, 2019 at 12:51
8

In Haskell, the closest you have is "class". This class though not as same as the class in Java and C++ , will work for what you want in this case.

In your case this is how your code will look.

class Animal a where 
say :: String -> sound 

Then you can have individual data types adapting these methods.

instance Animal Dog where
say s = "bark " ++ s 

EDIT :- Before you can specialize say for Dog you need to tell the system that Dog is animal.

data Dog =  \--something here --\ (deriving Animal)

EDIT :- For Wilq.
Now if you want to use say in a function say foo, you will have to tell haskell that foo can only work with Animal.

foo :: (Animal a) => a -> String -> String
foo a str = say a str 

now if you call foo with dog it will bark, if you call with cat it will meow.

main = do 
let d = dog (\--cstr parameters--\)
    c = cat  
in show $ foo d "Hello World"

You now can not have any other definition of function say. If say is called with anything which is not animal, it will cause compile error.

3
  • ill have to real a little more on haskell to understand thi fully, but i think i get the jist of it. im still curious though how this would line up with more a complex code base.
    – skift
    Commented Dec 19, 2012 at 7:44
  • nitpick Animal should be capitalized Commented Dec 20, 2012 at 0:55
  • 1
    How does the say function know that you call it on a Dog if it only takes a String? And isn't "deriving" only for some built-in classes?
    – WilQu
    Commented Dec 20, 2012 at 12:43
6

Functional languages use 2 constructs to achieve polymorphism:

  • First order functions
  • Generics

Creating polymorphic code with those is completely different than how OOP uses inheritance and virtual methods. While both of those might be available in your favorite OOP language (like C#), most functional languages (like Haskell) kick it up to eleven. It is rare to function to be non-generic and most functions have functions as parameters.

It is hard to explain like this and it will require lot of your time to learn this new way. But to do this, you need to completely forget OOP, because that's not how it works in functional world.

9
  • 2
    OOP is all about polymorphism. If you think OOP is about having functions tied to your data, then you know nothing about OOP.
    – Euphoric
    Commented Dec 19, 2012 at 7:32
  • 4
    polymorphism is just one aspect of OOP, and I think not the one the OP is really asking about.
    – Doc Brown
    Commented Dec 19, 2012 at 7:34
  • 2
    Polymorphism is key aspect of OOP. Everything else is there to support it. OOP without inheritance/virtual methods is almost exactly same as procedural programming.
    – Euphoric
    Commented Dec 19, 2012 at 7:38
  • 1
    @ErikReppen If "apply an interface" is not needed often, then you are not doing OOP. Also, Haskell has modules too.
    – Euphoric
    Commented Dec 19, 2012 at 8:15
  • 1
    You don't always need an interface. But they are highly useful when you do need them. And IMO another important part of OOP. As for modules go in Haskell, I think this is probably closest to OOP for functional languages, as far as code organization is concerned. At least from what I have read so far. I know they're still very different.
    – skift
    Commented Dec 19, 2012 at 8:34
0

it really depends on what you want to accomplish.

if you just need a way to organize behaviour based on selective criteria, you can use e.g. a dictionary (hash-table) with function-objects. in python it could be something along the lines of:

def bark(what):
    print "barks: {0}".format(what) 

def meow(what):
    print "meows: {0}".format(what)

def climb(how):
    print "climbs: {0}".format(how)

if __name__ == "__main__":
    animals = {'dog': {'say': bark},
               'cat': {'say': meow,
                       'climb': climb}}
    animals['dog']['say']("ruff")
    animals['cat']['say']("purr")
    animals['cat']['climb']("well")

note however, that (a) there are no 'instances' of dog or cat and (b) you will have to keep track of the 'type' of your objects yourself.

like for example: pets = [['martin','dog','grrrh'], ['martha', 'cat', 'zzzz']]. then you could do a list comprehension like [animals[pet[1]]['say'](pet[2]) for pet in pets]

0

OO Languages can be used in place of low-level languages sometimes to interface directly with a machine. C++ For sure, but even for C# there are adapters and such. Though writing code to control mechanical parts and have minute control over memory are best kept as close to low-level as possible. But if this question is related to current Object-Oriented software like Line Of Business, web applications, IOT, Web Services, and the majority of mass used applications, then...

Answer, if applicable

Readers might try working with a Service-Oriented Architecture (SOA). That is, DDD, N-Layered, N-Tiered, Hexagonal, whatever. I haven't seen a Large business application efficiently use "Traditional" OO (Active-Record or Rich-Models) as it was described in the 70's and 80's very much in the last decade+. (See Note 1)

The fault isn't with the OP, but there are a couple problems with the question.

  1. The example you provide is simply to demonstrate Polymorphism, it isn't production code. Sometimes examples exactly like that are taken literally.

  2. In FP and SOA, Data is separated from Business Logic. That is, Data and Logic don't go together. Logic goes into Services, and Data (Domain Models) does not have Polymorphic behavior (See Note 2).

  3. Services and Functions can be Polymorphic. In FP, you frequently pass functions as parameters to other functions instead of values. You can do the same in OO Languages with types like Callable or Func, but it doesn't run rampant (See Note 3). In FP and SOA, your Models aren't Polymorphic, only your Services/Functions. (See Note 4)

  4. There is a bad case of hardcoding in that example. I'm not only talking about the red colored string "dog barks". I'm also talking about the CatModel and DogModel themselves. What happens when you want to add a Sheep? You have to go into your code and create new code? Why? In production code, I would rather see just an AnimalModel with its properties. At worst, an AmphibianModel and a FowlModel if their properties and handling are so different.

This is what I'd expect to see in a current "OO" Language:

public class Animal
{
    public int AnimalID { get; set; }
    public int LegCount { get; set; }
    public string Name { get; set; }
    public string WhatISay { get; set; }
}

public class AnimalService : IManageAnimals
{
    private IPersistAnimals _animalRepo;
    public AnimalService(IPersistAnimals animalRepo) { _animalRepo = animalRepo; }

    public List<Animal> GetAnimals() => _animalRepo.GetAnimals();

    public string WhatDoISay(Animal animal)
    {
        if (!string.IsNullOrWhiteSpace(animal.WhatISay))
            return animal.WhatISay;

        return _animalRepo.GetAnimalNoise(animal.AnimalID);
    }
}

Basic Flow

How do you move from Classes in OO to Functional Programming? As others have said; You can, but you don't really. The point of the above is to demonstrate that you shouldn't even be using Classes (in the traditional sense of the world) when doing Java and C#. Once you get to writing code in a Service-Oriented Architecture (DDD, Layered, Tiered, Hexagonal, whatever), you'll be one step closer to Functional because you separate your Data (Domain Models) From your Logical Functions (Services).

OO Language one step closer to FP

You might even take it a bit further and split your SOA Services into two types.

Optional Class Type 1: Common Interface-Implementing Services for Entry Points. These would be "impure" Entry-Points which can call into "Pure" or "Impure" other functionality. This might be your Entry Points from a RESTful API.

Optional Class Type 2: Pure Business Logic Services. These are Static Classes which have "Pure" functionality. In FP, "Pure" means there are no side effects. It doesn't explicitly set State or Persistence anywhere. (See Note 5)

So when you think of Classes in Object-Oriented Languages, being used in a Service-Oriented Architecture, it not only benefits your OO Code, it begins to make Functional Programming seem very easy to understand.

Notes

Note 1: Original "Rich" or "Active-Record" Object-Oriented Design is still around. There's a LOT of legacy code like that back when people were "doing it right" a decade or more ago. Last time I saw that kind of code (done correctly) was from an video game Codebase in C++ Where they were controlling memory precisely and had very limited space. Not to say FP and Service-Oriented Architectures are beasts and shouldn't consider hardware. But they place the ability to constantly change, be maintained, have variable data sizes, and other aspects as priority. In video games and machine AI, you control the signals and data very precisely.

Note 2: Domain Models do not have Polymorphic Behavior, nor do they have External Dependencies. They are "Isolated". That doesn't mean they have to be 100% Anemic. They can have a lot of logic related to their construction and mutable property alteration, if such applies. See DDD "Value Objects" and Entities by Eric Evans and Mark Seemann.

Note 3: Linq and Lambda's are very common. But when a user creates a new function, they rarely use Func or Callable as parameters, whereas in FP it would be weird to see an app without functions following that pattern.

Note 4: Not confusing Polymorphism with Inheritance. A CatModel might inherit AnimalBase to determine which Properties an Animal typically has. But as I show, Models like this are a Code Smell. If you see this pattern, you might consider breaking it down and turning it into data.

Note 5: Pure functions can (and do) accept functions as parameters. The incoming function might be impure, but might be pure. For testing purposes, it would always be pure. But in production, though it is treated as pure, it might contain side-effects. That doesn't change the fact that the pure function is pure. Though the parameter function might be impure. Not confusing! :D

-2

You could do something like this .. php

    function say($whostosay)
    {
        if($whostosay == 'cat')
        {
             return 'purr';
        }elseif($whostosay == 'dog'){
             return 'bark';
        }else{
             //do something with errors....
        }
     }

     function speak($whostosay)
     {
          return $whostosay .'\'s '.say($whostosay);
     }
     echo speak('cat');
     >>>cat's purr
     echo speak('dog');
     >>>dogs's bark
2
  • 1
    I haven't given any negative votes. But my guess is that it is because this approach is neither functional not object oriented.
    – Manoj R
    Commented Dec 19, 2012 at 13:20
  • 1
    But the concept conveyed is close to the pattern matching used in functional programming, i.e. $whostosay becomes the object type that determines what gets executed. The above can be modified to additionally accept another parameter $whattosay so that a type that supports it (e.g. 'human') can make use of it.
    – syockit
    Commented Nov 14, 2013 at 17:20

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.