Instantiation in Classic Languages

I repeat here a pattern in six languages. In each case there is a function cc of no arguments that returns a pair of functions, the first to increment a pointer and the second to report the counter value. Each invocation of cc creates a new counter. I view this as a plausibly useful function in a highly useful pattern.

C++; Java; Algol 68; C; OCaml; Scheme;——Keykos

I consider the C++ and Java samples to be the newer class based pattern.
The Algol 68 and C versions don’t work because the storage for variable count does not survive the invocation of cc. The point of the exercise is that their syntax and most of their semantics supports the pattern.
The C syntax uses a gcc extension to C, supported by many compilers.
The Algol68 interpreter, whose diagnostic follows the program, checks expired scopes at runtime.
This construction is specifically supported by Scheme and OCaml.

Java and C++ have other native syntaxes for initialization, but they rely more of the language definition.

I prefer the patterns used in Algol 68, C, OCaml, Scheme as they do the job with less conceptual overhead. It can be argued that the compiler has a new job to discover that the variable count cannot be an ordinary stack variable. The AWRE Algol 68 compiler did just that and this program was valid there.

An advantage of the closure pattern, (OCaml & Scheme) is that the caller of cc can delegate the two resulting functions to two separate deputies and know that the first deputy cannot read the counter and that the second cannot increment it. I do not know how to do this easily in the Java or C++ pattern.

The class patterns have an advantage in sibling access where an object of the class is passed to a function in the class. The function can see inside the object. My closure pattern here does not support that without the sealer-unsealer primitive or some other form of synergy.

I do not see how to do this in Apple’s block construct which produces just one function per new environ.

Scaling Up

The sample here is comically small, yet useful. The pattern can be scaled up to large projects where protection between objects of the ‘same class’ becomes strategic. Notice that functions defining the behavior of the client servers have only the data of their particular client in scope and are thus unable to express the mixing of client data. I think that Mach, as applied to file system logic, fails to provide this separation.

Data abstraction is:

  1. to be used by code to hide the data that represents an abstract state from any other code,
  2. (in my opinion) to ensure that the code that does understand the data, is not burdened with job of distinguishing between its clients and their respective data.
This is nearly effortless in Scheme, OCaml, C++ and Java; further it happens naturally without thinking about it—just a natural way of doing things in a lexically scoped language.