Expression problem related to OO and FP
This was written somewhere else, by someone who probably did a better job explaining it than I’m doing. But I can’t find that link, so here goes…
In the common ways in which problems are deconstructed in OO and FP there are tradeoffs in the future extensibility of the program. Take the following two examples, in pseudo Haskell and C# respectively.
Haskell, FP approach
type Shape
= Square
| Circledisplay :: Shape -> String
display Square = "Square"
display Circle = "Circle"sides :: Shape -> Int
sides Square = 4
sides Circle = 1
C#, OO approach
interface IShape {
string Display();
int Sides();
}class Square : IShape {
public int Sides() { return 4; }
public string Display() { return "Square"; }
}class Circle : IShape {
public int Sides() { return 1; }
public string Display() { return "Circle"; }
}
In both cases we have 2 inhabitants of a type and 2 functions that can act upon all inhabitants of the type.
Adding a new Shape
Now imagine we want to add a new shape. In the OO approach we simply add another class that implements IShape
and we’re done; there’s no need to touch Square
, Circle
, or IShape
.
class Triangle : IShape {
public int Sides() { return 3; }
public string Display() { return "Triangle"; }
}
The FP approach requires more of a refactor. We have to add a case to our Shape
type and update all functions that know about our Shape
type.
type Shape
= Square
| Circle
| Triangledisplay :: Shape -> String
display Square = "Square"
display Circle = "Circle"
display Triangle = "Triangle"sides :: Shape -> Int
sides Square = 4
sides Circle = 1
sides Triangle = 3
In the case of adding inhabitants to a type, the OO approach is far less work than the FP approach. In fact, this is exactly where OO shines because it organizes code in such a way that it easily allows future inhabitants of types.
Adding a new function
Now let us imagine that we need to do something else with our Shape type. Let’s say that Square and Circle are all the shapes we need and we now need to be able to calculate their areas.
In the FP approach this change is trivial
area :: Shape -> Number -> Number
area Square x = x * x
area Circle x = 3.14 * (x * x)
This time it’s the OO approach that requires significant refactoring as we have to update the interface and all classes implementing the interface.
interface IShape {
string Display();
int Sides();
double Area(double radius);
}class Square : IShape {
public int Sides() { return 4; }
public string Display() { return "Square"; }
public double Area(double radius) { return radius * radius; }}class Circle : IShape {
public int Sides() { return 1; }
public string Display() { return "Circle"; }
public double Area(double radius) { return 3.14 * (radius * radius); }
}
Summary
FP code tends to favor Algebraic Data types which have a fixed number of type inhabitants but that can have any number of functions that act upon the type. OO code tends to favor interfaces with a fixed number of functions, which allow any number of classes to implement the interface.