Programming Language for Old Timers

by David A. Moon
February 2006 .. September 2008

Comments and criticisms to dave underscore moon atsign alum dot mit dot edu.

Previous page   Table of Contents   Next page


Destructuring occurs when an invocation of a constructor appears in a left-hand-side position. The object on the right-hand-side must be the type of object that the constructor would construct. The object is disassembled into its component parts and each argument of the constructor is placed on the left-hand side with the corresponding part as its right-hand side. Destructuring is allowed when and only when a destructuring macro corresponding to the constructor has been defined. The name of the destructuring macro is the name of the constructor suffixed by ":=". For example, corresponding to the list constructor is the list:= destructuring macro which expands into assignments of parts of the list to its arguments.

Destructuring is allowed in assignment, as explained in the Assignment section above. It is also allowed in the def statement and in parameter-lists. This is implemented by expanding the destructuring macro as if the containing expression was an assignment, then rewriting the resulting P-expressions as definitions rather than assignments.

In a def statement, the last argument to the destructuring macro is the right-hand side. In a parameter-list, the last argument to the destructuring macro is a place-holder variable that will receive the corresponding argument to the function. The type restriction of the place-holder defaults to the type-specifier of the first definition in the expansion of the destructuring macro whose right-hand side is the place-holder, rather than defaulting to $anything.

The expansion of the destructuring macro must be an assignment, a collation, or a scopation. The sub-expressions of a collation or scopation can be assignments, additional levels of collation or scopation, and other expressions. Each assignment within the expansion whose left-hand side is not defined in a scope inside the expansion is rewritten as a definition of that variable. This definition appears in the outer scope, not in any scopation that is part of the expansion; there is no built-in way to do that special scoping in source code but it is easily done in P-expressions.

Examples of destructuring in the def statement:

def list(a, b, c) = d
This first translates into a macro call
list:=(a, b, c, d)
which expands into
  def temp is list = d
  a := temp[0]
  b := temp[1]
  c := temp[2]
which the def macro rewrites as the final expansion
  def temp is list = d
  def a = temp[0]
  def b = temp[1]
  def c = temp[2]
except the definitions of a, b, and c are not scoped in their immediately containing block but instead in the scope where the def appeared.

Destructuring can be nested:

def list(a, list(b, c)) = f(y)
turns into
  def temp1 is list = f(y)
  def a = temp1[0]
    def temp2 is list = temp1[1]
    def b = temp2[0]
    def c = temp2[1]

Example of destructuring in a parameter list:

defun f(list(a, b), c) a + b + c
expands the macro call
list:=(a, b, arg1)
  def temp is list = arg1
  a := temp[0]
  b := temp[1]
which the parameter-list parser and the defun statement rewrite as
defun f(arg1 is list, c)
  def temp is list = arg1
  def a = temp[0]
  def b = temp[1]
  a + b + c

The same example can be written more concisely using the prefix [ operator:

defun f([a, b], c) a + b + c

Here is how to define the list destructor macro:

defmacro list:= ( ?arg & , ^^ ) =>
  def rhs = last(arg)
  def assignments = for i from 0 below arg.length - 1,
                        a in arg
                      collect `?a := temp[?i]`
     def temp is list = ?rhs
     { ?assignments & ^ }*`

Previous page   Table of Contents   Next page