Closures as Objects

As objects, closures lack two significant features: Method dispatch is a syntactic convenience and perhaps a performance advantage. Synergy is more fundamental.

Below is a function that returns an immutable set abstraction where you can add members and query membership:

(define em (let ms ((s '()))
   (let ((query (lambda (x)
   (let l ((s s)) (and (pair? s) (or (eq? x (car s)) (l (cdr s))))))))
   (cons
     (lambda (x) (ms (if (query x) s (cons x s)))) ; adder
     query))))
em is the empty set. If s is a set then ((car s) x) is the new set s∪{x} and ((cdr s) x) is x∈s.
((cdr em) 6) ; ⇒ #f; 6 ∉ {}
(define b ((car em) 6)) ; b = {6}
((cdr b) 5) ; ⇒ #f ; 5 ∉ {6}
((cdr b) 6) ; ⇒ #t ; 6 ∈ {6}
((cdr em) 6) ; ⇒ #f; 6 ∉ {} still
(define c ((car ((car b) 9)) 7)) ; c = {6 9 7}
((cdr c) 6) ; ⇒ #t; 6 ∈ {6 9 7}
((cdr c) 7) ; ⇒ #t; 7 ∈ {6 9 7}
((cdr c) 8) ; ⇒ #f; 8 ∉ {6 9 7}
((cdr c) 9) ; ⇒ #t; 9 ∈ {6 9 7}
Scheme and Lisp both lack structures with named fields which aid the syntax. Another disadvantage is that the pair of functions duplicates the reference to the shared environment via which s is accessed by the pair of functions. This pattern has an advantage, however. I may need to pass the query function across a trust boundary while withholding the adder function.

Selecting methods is not mnemonic in this style, but the data is actually abstracted. More vitally it appears impossible to add a set union operation for inability extend this pattern to include synergy. If we pass a set to a function within the set abstraction, that function is unable to reach into the passed set to get its members.

If I want to provide the function of adding all the elements of one set to another, there is no place for code with access to the representation of both sets. This required synergy comes naturally to conventional statically typed OO languages. The representation of one of the two sets is always abstracted when we use closures as objects.

Classic object oriented languages have rules for when things are initialized. I often find these rules obscure and not what I need. Initialization code is conveniently located in closure patterns. For instance it we had wanted the initial sets to contain the first three odd numbers we would merely have replaced '() by '(1 3 5).

use-case
OO languages provide synergy almost as an afterthought. It does not come for free with closures. See the Safe for one proposal to add to the foundation to support synergy.