Lunar Programming Language

by David A. Moon
January 2017 - January 2018



Bundles

Lunar programs frequently use the same name for two related but conceptually distinct objects, for example a class and its constructor, or an operator and the function it invokes. Since in a given scope a name can only have one value, Lunar uses bundle objects to combine multiple natures into one datum.

A bundle combines up to three different "natures." Each nature is the name of an abstract class whose members are all bundles that have that nature. The slots that store the attributes of all three natures exist in all bundles, but the slots for a nature are only used if the bundle has that nature.

Nature Purpose Attributes
class A class defines object structure and type slots, superclasses, modifiers, disjoint
function A function defines behavior methods, requirements, destructuring
operator An operator directs parsing arity, precedence, macro expanders

Class nature defines the structure and type of members of that class as well as relationships with superclasses. It also contains the set of classes that are declared to be disjoint with this class.

Function nature bundles together a set of methods that define the behavior of the function. It also includes an optional destructuring method used at compile time.

Operator nature is both for unary/binary/ternary operators, which are invoked with a special algebraic expression syntax with left and right precedence but take ordinary expressions as their operand(s), and for prefix/infix macros, which do their own parsing so they can be invoked with idiosyncratic syntax. Operator nature is only used at compile time.

In addition to slots to store the attributes of all three natures, bundles have a name slot. This is useful for interactive debugging, and allows a reference to a bundle from separately compiled code to be linked to the corresponding bundle when that code is loaded into a new runtime. It is permitted, but unusual, to create an anonymous bundle with a false name.

The natures of a bundle can change dynamically as new definitions are executed. To support this, bundles have an unusual metamorphic quality. The class bundle has seven direct subclasses; these eight classes correspond to the eight possible combinations of the three natures. All eight classes have identical structure, but they have different superclasses in addition to bundle that correspond to the natures that are active. When a nature is added to or removed from a bundle, its class morphs to the appropriate subclass of bundle or to bundle itself if all natures are removed.

bundle could have been defined by

def arity_name = set(#unary, #binary, #ternary, #prefix, #infix)

defclass bundle(name name | false)
  name = name                           name | false

  ;; Class nature
  slots := []                           list
  superclasses := []                    list
  abstract := false                     boolean
  intrinsic := false                    boolean
  sealed := false                       boolean
  autothrow := false                    boolean
  noreturn := false                     boolean
  instance_description := false         instance_description | false

  ;; Function nature
  methods := []                         list
  requirements := []                    list
  destructuring_method := false         method | false

  ;; Operator nature
  arity := set[arity_name]()            set[arity_name]
  left_precedence := 0                  0..99
  right_precedence := 0                 0..99

  ;; Macro facet of operator nature
  prefix_expander := false              method | false
  infix_expander := false               method | false
We could save space by storing each nature in a subsidiary structure referenced by a pointer that is false when the nature is not present, but the slot-based interface would be the same, using . methods.

The three abstract nature superclasses are:

;; All class bundles inherit from this
abstract:
defclass class

;; All function bundles inherit from this, and so do methods and exit functions
abstract:
defclass function

;; All operator bundles inherit from this
abstract:
defclass operator
None of these classes have slots.

The seven additional bundle classes are:

defclass class_bundle                   bundle, class
defclass function_bundle                bundle, function
defclass class_function_bundle          bundle, class, function
defclass operator_bundle                bundle, operator
defclass class_operator_bundle          bundle, class, operator
defclass function_operator_bundle       bundle, function, operator
defclass class_function_operator_bundle bundle, class, function, operator
These classes are not abstract, but they do not have constructors. A direct instance can only be created by morphing.

None of these classes are sealed. If you wish to use metaclass programming, you can define your own metaclass, which typically would inherit from class_function_bundle and cannot morph. A metaclass cannot inherit directly from class since it must be a bundle. A metaclass can add its own slots if desired.

The only use of metaclasses built into Lunar is for singleton classes. A singleton class is a subclass of class_bundle.


Previous page   Table of Contents   Next page



Creative Commons License
Lunar by David A. Moon is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Please inform me if you find this useful, or use any of the ideas embedded in it.
Comments and criticisms to dave underscore moon atsign alum dot mit dot edu.