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