Expression Problem

The "expression problem" is a phrase used to describe a dual problem that neither ObjectOrientedProgramming nor FunctionalProgramming fully addresses.

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.

In FunctionalProgramming, 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)

In ObjectOrientedProgramming, 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

The 'ExpressionProblem' manifests when you wish to 'extend' the set of objects or functions. And that is the heart of the ExpressionProblem.

The ExpressionProblem is a specific example of a larger class of problems known generally as CrossCuttingConcerns - 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 HyperSpaces motivating example specifically targets this problem).

In OopArgumentsDebatesAndDiscussion, the ExpressionProblem is mentioned briefly in a case against DomainObjects. The reasoning: the main purpose of DomainObjects is to associate a domain ObjectIdentifier (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 DomainObjects 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 DomainObjects.

The OopArgumentsDebatesAndDiscussion page does not argue that FunctionalProgramming is a better answer, only that DomainObjects are one wrong answer that runs into this problem.

Here is an implementation that shows how to sidestep the problem, in C++:

It's not sidestepping if you actually solve the problem. That looks like a promising start in CeePlusPlus.

The VisitorPattern 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.

Related: SwitchStatementsSmell

View edit of November 24, 2013 or FindPage with title or text search