the Expression Problem and its solutions - [PROGRAMMING]

Zenaan Harkness zen at freedbms.net
Tue Oct 9 19:25:43 PDT 2018


The Expression Problem is faced by all programmers who create
anything other than simple programs.

Represent abstractions with types, add procedures, methods or
functions (choose your term) to manipulate those types, and some time
later, one is invariably faced with the 2 problems:

 - adding new types/ classes
 - adding new operations/ functions

This be the essence of the problem of programming abstractions.

Eli Bendersky does a fine job of both laying out this "fundamental"
problem of computing and the traditional approaches to solving this
problem, namely:

 - OO programming with syntax for classes (syntactically co-located
   data with the operations on that data), whereby adding types is
   relatively straightforward (provided for syntactically);
   whilst adding operations requires changing function sets or
   "interfaces", which in general requires more than merely adding
   functions, impacting (undesirably) the type declarations
   (classes).

 - functional programming inverts this ease of modification aspect,
   since operations are the first order syntax, which thus leads the
   programmer to design his program with functions/ operations as
   primal, thus adding functions is the simple program extension
   mechanism just like adding data types or classes is the simple OO
   extension mechanism;
   whilst adding new data types in the functional language requires
   all existing functions to be (again, undesirably) modified to
   handle the new data type.

The same "expression problem" thus manifests from either side of the
programming language spectrum.

Velly interdasting.


Bendersky lays it out clearly, and with nice little matrix PNG
images, then goes on with the (relatively, at least in C++) complex
"visitor pattern" which is typically used to solve this problem in
C++, using virtual multiple inheritance and dynamic type checking -
not the simplicity we crave for our programming solution baskets.


Enter the White Knight, Clojure, with syntax so powerful only Lisp
dialects raise their heads in a collective superiority sneer.

The secret? Clojure syntactically hides multiple dispatch behind
reasonably elegant syntax - so the performance hit is there, but at
least achieving the result is not a syntactic nightmare of virtual
multiple inheritance + RTTI functionality or some ungodly template
syntax.

But it's actually only single dispatch? Yes, there be more lurking
secrets - what Clojure calls "open methods":

  “Note a crucial difference between how methods are defined in
  C++/Java and in Clojure. In C++/Java, methods have to be part of a
  class and defined (or at least declared) in its body. You cannot
  add a method to a class without changing the class's source code.
  
  In Clojure, you can. In fact, since data types and multimethods are
  orthogonal entities, this is by design. Methods simply live outside
  types - they are first class citizens, rather than properties of
  types. We don't add methods to a type, we add new methods that act
  upon the type. This doesn't require modifying the type's code in
  any way (or even having access to its code).”


Clojure "protocols" (from Java POV, "simple, usuall single-method
Interfaces) also get a look in. Here's the source, Luke:

  The Expression Problem and its solutions
  https://eli.thegreenplace.net/2016/the-expression-problem-and-its-solutions/

Bendersky even does a second round - recommended:

  More thoughts on the Expression Problem in Haskell
  https://eli.thegreenplace.net/2018/more-thoughts-on-the-expression-problem-in-haskell/


So notwithstanding that Clojure runs on the JVM, note Java's first
class syntactic citizens are classes (in comparison to Clojure's
first class functions):
  java - What is a first class citizen function? - Stack Overflow
  https://stackoverflow.com/questions/5178068/what-is-a-first-class-citizen-function
  “So, objects are the first class citizens in java. Admittedly,
  java8 supports passing of methods (method behavior, to be precise)
  to other methods using functional interfaces and lambda
  expressions. But that does not mean that java has functions as
  first class citizens.”

Note that Java 8 syntactically adds "first class functions" which are
represented internally/ in the JVM, as classes (perhaps this is how
Clojure runs on the JVM?):

  Java 8: Simple Example of First-class Functions
  http://4dev.tech/2015/08/java-8-simple-example-of-first-class-functions/

(Observing Java's predicates and other such Lisp wanna be syntax,
 it's rather fugly IMEHO.)


The link to Bendersky was highlighted by Stephen Mann in his this
week's mailing list mailout, where he also links to his recent blog
on "good names" in programming:

  Good Code Depends on Good Names
  https://stephenmann.io/post/good-code-depends-on-good-names/

I can't find his email list archives, but here's his blog index:
http://stephenmann.io/



More information about the cypherpunks mailing list