The "expression problem" is a phrase used to describe a dual problem that neither ObjectOrientedProgramming
The basic problem can be expressed in terms of a simple example: Suppose you wish to describe shapes, including rectangles and circles, and you wish to compute the areas.
, you would describe a data type such as:
type Shape = Square of side
| Circle of radius
Then you would define a single area function:
define area = fun x -> case x of
Square of side => (side * side)
| Circle of radius => (3.14 * radius * radius)
, you would describe the data type such as:
class Shape <: Object
virtual fun area : () -> double
class Square <: Shape
side : double
area() = side * side
class Circle <: Shape
radius : double
area() = 3.14 * radius * radius
' manifests when you wish to 'extend' the set of objects or functions.
- If you want to add a 'triangle' shape:
- the ObjectOrientedProgramming approach makes it easy (because you can simply create a new class)
- but FunctionalProgramming makes it difficult (because you'll need to edit every function that accepts a 'Shape' parameter, including 'area')
- OTOH, if you want add a 'perimeter' function:
And that is the heart of the ExpressionProblem
is a specific example of a larger class of problems known generally as CrossCuttingConcern
s - in this particular case the relevant 'concerns' being 'the set of shapes' and 'the features of shapes'. Many languages include designs to help solve the ExpressionProblem
. Open functions (functions that can be extended with new pattern-matches), open data-types (data types that can be extended with new patterns), and MultiMethods
('open' specialized polymorphic functions with 'open' set of classes), and PredicateDispatching
, are all viable approaches.
More general solutions to SeparationOfConcerns
will also apply (e.g. IBM's HyperSpace
s motivating example specifically targets this problem).
, the ExpressionProblem
is mentioned briefly in a case against DomainObject
s. The reasoning: the main purpose of DomainObject
s is to associate a domain O
bjectIdentifier (see ObjectIdentity
) with a set of domain features (properties). Use of OOP methods (e.g. synchronous MessagePassing
with return values) to solve this problem generally requires: (a) classifying each object identifier into a 'class' that chooses a constructor for it (a problem that runs into LimitsOfHierarchies
), then (b) anticipating which 'features' might need to be computed from these objects (e.g. stylized printing, verification, cost estimates, etc.) that the features may be named in the hierarchy. Requirement (b) runs into the ExpressionProblem
, since any missed features will cut across classes... and, in corollary, any supported feature will increase the responsibilities embedded in code (generally making it less reusable across programs).
As opposed to a more specific class of computation-domain objects (math, language, queues and stacks, functors, values, etc.) this is especially problematic in general DomainObject
s because there is no complete set of 'defining' features for a given object, so one is never finished adding or removing features across the set of DomainObject
page does not argue that FunctionalProgramming
is a better answer, only that DomainObject
s are one
wrong answer that runs into this problem.
Here is an implementation that shows how to sidestep the problem, in C++:
sidestepping if you actually solve the problem. That looks like a promising start in CeePlusPlus
in OOP lets you switch to the other side of the problem, by making it easy to add new operations and hard to add new objects. Though of course, it comes with the cost of setting up the pattern.