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"
  https://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.

Defined variables (0)

Defined functions (48)

accessor--internal-p(OCLOSURE)
accessor--slot(OBJ)
accessor--type(OBJ)
cconv--interactive-helper(FUN IF)
cconv--interactive-helper--fun(OBJ)
cconv--interactive-helper--if(OBJ)
cconv--interactive-helper--internal-p(OCLOSURE)
oclosure--accessor-cl-print(OBJECT STREAM)
oclosure--accessor-copy(OBJ TYPE SLOT INDEX)
oclosure--accessor-docstring(F)
oclosure--build-class(NAME DOCSTRING PARENT-NAMES SLOTS)
oclosure--class-allparents(CL-X)
oclosure--class-allparents--cmacro(CL-WHOLE-ARG CL-X)
oclosure--class-docstring(CL-X)
oclosure--class-docstring--cmacro(CL-WHOLE-ARG CL-X)
oclosure--class-index-table(CL-X)
oclosure--class-index-table--cmacro(CL-WHOLE-ARG CL-X)
oclosure--class-make(NAME DOCSTRING SLOTS PARENTS ALLPARENTS)
oclosure--class-name(CL-X)
oclosure--class-name--cmacro(CL-WHOLE-ARG CL-X)
oclosure--class-p(CL-X)
oclosure--class-p--cmacro(CL-WHOLE-ARG CL-X)
oclosure--class-parents(CL-X)
oclosure--class-parents--cmacro(CL-WHOLE-ARG CL-X)
oclosure--class-slots(CL-X)
oclosure--class-slots--cmacro(CL-WHOLE-ARG CL-X)
oclosure--copy(OCLOSURE MUTLIST &rest ARGS)
oclosure--define(NAME DOCSTRING PARENT-NAMES SLOTS &rest PROPS)
oclosure--define-functions(NAME COPIERS)
oclosure--defstruct-make-copiers(COPIERS SLOTDESCS NAME)
oclosure--fix-type(IGNORE OCLOSURE)
oclosure--get(OCLOSURE INDEX MUTABLE)
oclosure--index-table(SLOTDESCS)
oclosure--lambda(TYPE BINDINGS MUTABLES ARGS &rest BODY)
oclosure--p(OCLOSURE)
oclosure--set(V OCLOSURE INDEX)
oclosure--set-slot-value(OCLOSURE SLOTNAME VALUE)
oclosure--slot-index(OCLOSURE SLOTNAME)
oclosure--slot-mutable-p(SLOTDESC)
oclosure--slot-value(OCLOSURE SLOTNAME)
oclosure-accessor--index(OBJ)
oclosure-accessor--internal-p(OCLOSURE)
oclosure-accessor--slot(OBJ)
oclosure-accessor--type(OBJ)
oclosure-define(NAME &optional DOCSTRING &rest SLOTS)
oclosure-lambda(TYPE-AND-SLOTS ARGS &rest BODY)
oclosure-type(OCLOSURE)
save-some-buffers-function--p(OCLOSURE)

Defined faces (0)