In this tagged language design for Vicare: one day everything looks fine, the next day everything looks wrong. For sure I am having some ideas that would be hard to implement efficiently and maybe quite weird to use. In the last entry on the tagged language (see Musings on the tagged language (part 4) (2015 February 18)) I left myself with the idea of implementing function overloading, which means having the following expansions:
(length '(1 2)) → (list-length '(1 2)) (length '#(1 2)) → (vector-length '#(1 2)) (length '#vu8(1 2)) → (bytevector-length '#vu8(1 2)) (length "1 2") → (list-length "1 2")
but function overloading should not interfere with macro expansion; the code:
(import (vicare)) (add-method length (<string>) string-length) (define (frob obj) ---) (let-syntax ((length (syntax-rules () ((_ ?expr) (frob ?expr)) ))) (length "ciao"))
should cause the following expansion to happen:
(length "ciao") → (frob "ciao")
is this actually doable?
Let’s step back one moment. The following works and is already implemented in
(vicare)
:
("ciao" length) ⇒ 4
because first the expander determines the type of "ciao"
to be <string>
,
then it searches the name length
in the table of methods in <string>
.
What should happen in the following:
(length "ciao") ⇒ 4
is not clear. Should the expander first search for a binding named length
using normal bindings resolution, then visit the methods table only if no syntax with
such name exists in the lexical context? And if no method named length
exists: should it go back in the lexical context to search for a non–syntax binding?
This going back and forth is inefficient and confusing.
By using a method call syntax:
(method-call length "ciao")
everything is solved because we are explicitly declaring that we want to visit the table of methods. So we can keep normal bindings resolution.
Let’s say we change the reader to implement the following “quoting with dot”:
(.?symbol ?arg ...) → (method-call ?symbol ?arg ...)
using this syntax we could take the following function:
(define (list-of-strings? obj) (if (pair? obj) (and (string? (car obj)) (list-of-strings? (cdr obj))) (null? obj)))
and rewrite it as follows to generalise it to other implementations of lists (for example the immutable lists of srfi-116):
(define (list-of-strings? obj) (if (.pair? obj) (and (string? (.car obj)) (list-of-strings? (.cdr obj))) (.null? obj)))
does it look bad with all those dots?
What if the following sequence of transformations is implemented?
(.length "ciao") → (method-call length "ciao") → ("ciao" length)
we would have prefix notation and the same mechanism for querying the table of
methods already half–implemented in (vicare)
.
I want Vicare to be a practical language, not only a beautiful language as is
Scheme; for this reason I have included some syntaxes to implement loops with C
language style (while
, until
, do … while
, do …
until
): they look ugly in Scheme, but some people are used to them3.
Everybody outside the Lisp world likes interfaces: the gist of them is to give a name to a collection of method signatures which an object type can declare to implement. With Lisp notation it should look something like this:
(define-interface <shape> (method (draw (obj <shape>)))) (define-class <circle> (implements <shape>) (fields x-center y-center radius) (method (draw (O <circle>)) (actually-draw O)))
and, at expand–time, it is verified that the class <circle>
actually contains
definitions for the methods in <shape>
. This is possible if the method
definitions are inside the define-class
form.
What if I implement overloaded functions with clos–like syntax? They are not declared inside the type syntax, so would it be possible to implement interfaces?
They do
not look as ugly as loop
in Common Lisp, but still uglier than looping with
recursion. By the way: after having implemented a library providing Common Lisp
style restarts, I want loop
, too, in a standalone library. (There are so
many clauses!!! I dunno when I will find the will to implement it…)