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.
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.
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
:
<string>
; the expander must check that the multimethod has one argument only,
in which case the implementation is used in the expression.
length
in the lexical context of the expression. The result would
be to use the binding exported by (vicare)
.
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:
length
for <list>
goes in a table associated
to <list>
.
length
for <string>
goes in a table
associated to <string>
.
length
for <bytevector>
goes in a table
associated to <bytevector>
.
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.