File: oclosure.el.html
An OClosure is an object that combines the properties of records with those of a function. More specifically it is a function extended with a notion of type (e.g. for defmethod dispatch) as well as the ability to have some fields that are accessible from the outside.
See "Open closures", ELS'2022 (https://zenodo.org/record/6228797).
Here are some cases of "callable objects" where OClosures have found use:
- nadvice.el (the original motivation)
- kmacros (for cl-print and for kmacro-extract-lambda)
- cl-generic: turn cl--generic-isnot-nnm-p into a mere type test
(by putting the no-next-methods into their own class).
- Slot accessor functions, where the type-dispatch can be used to
dynamically compute the docstring, and also to pretty print them.
- save-some-buffers-function
Here are other cases of "callable objects" where OClosures could be used:
- Use the type to distinguish macros from functions.
- Use a name and depth property from the function passed to
add-function (or add-hook) instead of passing it via "props".
- iterators (generator.el), thunks (thunk.el), streams (stream.el).
- PEG rules: they're currently just functions, but they should carry
their original (macro-expanded) definition (and should be printed
differently from functions)!
- auto-generate docstrings for cl-defstruct slot accessors instead of
storing them in the accessor itself?
- SRFI-17's setter.
- coercion wrappers, as in "Threesomes, with and without blame"
https://dl.acm.org/doi/10.1145/1706299.1706342, or
"On the Runtime Complexity of Type-Directed Unboxing"
http://sv.c.titech.ac.jp/minamide/papers.html
- An efficient negate operation such that
(negate (negate f)) returns just f and (negate #'<) returns #'>=.
- Autoloads (tho currently our bytecode functions (and hence OClosures)
are too fat for that).
Related constructs:
- funcallable-standard-object (FSO) in Common-Lisp. These are different
from OClosures in that they involve an additional indirection to get
to the actual code, and that they offer the possibility of
changing (via mutation) the code associated with
an FSO. Also the FSO's function can't directly access the FSO's
other fields, contrary to the case with OClosures where those are directly
available as local variables.
- Function objects in Javascript.
- Function objects in Python.
- Callable/Applicable classes in OO languages, i.e. classes with
a single method called apply or call. The most obvious
difference with OClosures (beside the fact that Callable can be
extended with additional methods) is that all instances of
a given Callable class have to use the same method, whereas every
OClosure object comes with its own code, so two OClosure objects of the
same type can have different code. Of course, you can get the
same result by turning every oclosure-lambda into its own class
declaration creating an ad-hoc subclass of the specified type.
In this sense, OClosures are just a generalization of lambda which brings
some of the extra feature of Callable objects.
- Apply hooks and "entities" in MIT Scheme
https://www.gnu.org/software/mit-scheme/documentation/stable/mit-scheme-ref/Application-Hooks.html
Apply hooks are basically the same as Common-Lisp's FSOs, and "entities"
are a variant of it where the inner function gets the FSO itself as
additional argument (a kind of "self" arg), thus making it easier
for the code to get data from the object's extra info, tho still
not as easy as with OClosures.
- "entities" in Lisp Machine Lisp (LML)
https://hanshuebner.github.io/lmman/fd-clo.xml
These are arguably identical to OClosures, modulo the fact that LML doesn't
have lexically-scoped closures and uses a form of closures based on
capturing (and reinstating) dynamically scoped bindings instead.
Naming: OClosures were originally named FunCallableRecords (FCR), but
that name suggested these were fundamentally records that happened
to be called, whereas OClosures are really just closures that happen
to enjoy some characteristics of records.
The "O" comes from "Open" because OClosures aren't completely opaque
(for that same reason, an alternative name suggested at the time was
"disclosures").
The "O" can also be understood to mean "Object" since you have notions
of inheritance, and the ability to associate methods with particular
OClosure types, just as is the case for OO classes.