Musings on the tagged language (part 2) (2015 February 14 bis)

In a previous entry (see Musings on the tagged language (part 1) (2015 February 13 bis)) I discussed the problem of having type methods and field accessors with Lispy syntax in the tagged language; in particular the need to have all the methods available by importing only the identifier of the type, rather than all the identifiers of methods and field accessors.

The current situation

In the expression:

("ciao" length)

the literal expression "ciao" is considered of type <string> and the symbol length, that comes after it, is searched in the list of methods and field accessors of <string>. What matters is the symbol length whose name is the string "length"; it does not matter if length is an identifier that is bound in the lexical context of the expression.

This is not a Lisp–style solution.

A possible, more Lispy, solution

In the expression:

(length "ciao")

the literal expression "ciao" is considered of type <string> and the symbol length, that comes before it, is searched in the list of multimethods whose first argument is of type <string>. Again, what matters is the symbol length whose name is the string "length"; it does not matter if length is an identifier that is bound in the lexical context of the expression.

What the expander should do in the following situation:

(import (vicare))

(length "ciao")

is to first check if the class <string> contains a reference to a multimethod named length:

Assuming in future (vicare) implements an add-method syntax like (nausicaa) does, in the following example:

(import (vicare))

(add-method length (<list>)       length)
(add-method length (<string>)     string-length)
(add-method length (<bytevector>) bytevector-length)

(length "ciao")

the syntax uses of add-method would add methods implementations for length to the expand–time state of the classes <list>, <string> and <bytevector>; then the expression would be transformed to:

(string-length "ciao")

The library (nausicaa) already implements multimethods; in that implementation we could do:

(define-generic length (obj))

(add-method length (<list>)       length)
(add-method length (<string>)     string-length)
(add-method length (<bytevector>) bytevector-length)

the methods that specialise the generic function length are stored in a table in the state of the generic function; dispatching happens at run–time. No matter what the type of the arguments, all the methods go in the state of the generic function length which is associated to the identifier length.

In the hypothetical solution above, the difference would be that:

not a big difference. Most likely, much of the code that implements run–time dispatching for multimethods in (nausicaa) can be adapted to implement expand–time dispatching integrated in the expander.

Also, the expander code that parses ("ciao" length) as a “special syntax” can be adapted to parse (length "ciao") as a special syntax and fall back to the usual expression expansion when needed.