More work in the ‘typed-language’ branch of Vicare, for both the expander and the built–in types infrastructure. The matching machinery that determines if two type specifications are super–type and sub–type has seen further development, but it is still unfinished.
Everything I discuss here is relative to code in the head of the ‘typed-language’ branch.
Mixins are a way to add definition clauses to record–types and labels. Let’s consider this situation:
(define-record-type <alpha> (fields a)) (define-record-type <beta> (fields b)) (define-record-type <delta> (parent <alpha>) (fields v) (method (doit {O <delta>}) (+ 1 (.v O)))) (define-record-type <gamma> (parent <beta>) (fields v) (method (doit {O <gamma>}) (+ 1 (.v O))))
the definitions of <delta>
and <gamma>
share some clauses; both of them
already have a parent type and multiple inheritance is not supported by Vicare.
Is it possible to write the shared clauses only once and attach them to the
record–type definitions? Yes, with mixins. The example above is equivalent to the
following:
(define-record-type <alpha> (field a)) (define-record-type <beta> (field b)) (define-mixin <stuff> (field v) (method (doit {O <stuff>}) (+ 1 (.v O)))) (define-record-type <delta> (parent <alpha>) (mixins <stuff>)) (define-record-type <gamma> (parent <beta>) (mixins <stuff>))
the syntax use of define-mixin
associates a set of clauses to the identifier
<stuff>
; when the mixins
clause is used in the body of a record–type
definition:
<stuff>
are substituted with the identifier
of the enclosing record–type; <delta>
and <gamma>
in the example.
I have implemented late binding for overloaded functions:
(define/overload (doit {O <string>}) (list 'string O)) (define/overload (doit {O <fixnum>}) (list 'fixnum O)) (doit (cast-signature (<top>) "ciao")) ⇒ (string "ciao") (doit (cast-signature (<top>) 123)) ⇒ (fixnum 123)
Before this feature: whenever, at expand–time, a matching specialised function was not found, a syntax violation was raised. With this feature: late binding code is inserted and we get an error only at run–time when the function is actually called.
I do not like this very much, so I have added a new warning enabled with the command line option -Woverloaded-function-late-binding: whenever a matching function is not found at expand–time, a warning condition is raised. This warning is also enabled when using the new command line option -Wextra.
At present recursive type definitions are not supported. I want them. It is not possible to say this:
(define-type <list-syntax-object> (list-of <syntax-object>)) (define-type <vector-syntax-object> (vector-of <syntax-object>)) (define-type <syntax-object> (or <wrapped-syntax-object> <list-syntax-object> <vector-syntax-object>))
and it is not possible to say this:
(define-type <syntax-object> (or <wrapped-syntax-object> (list-of <syntax-object>) (vector-of <syntax-object>)))
Whenever the right–hand side of a define-type
use is processed: the
left–hand side syntactic identifier is bound (meaning that it is associated to a
label in the lexical environment), but the syntactic binding is still “displaced”
(meaning that the label is not yet associated to a syntactic binding descriptor).
Until now, I have been unable to devise an implementation that satisfies me. I am inclined towards using “forward declarations”, like the C language does; so the code above would look something like:
(define-type <syntax-object> (forward-definition)) (define-type <list-syntax-object> (list-of <syntax-object>)) (define-type <vector-syntax-object> (vector-of <syntax-object>)) (define-type <syntax-object> (or <wrapped-syntax-object> <list-syntax-object> <vector-syntax-object>))
but I do not know how it could be implemented internally: I would like an implementation with a small footprint.
At present, the definition of a record–type with constructor protocol looks like this:
(define-record-type <duo> (fields one two) (protocol (lambda (make-record) (lambda ({A <fixnum>} {B <fixnum>}) (make-record A B)))))
the type information of the constructor function’s arguments is not
propagated to the constructor syntax (new <duo> 1 2)
.
This is because the expression in the protocol
clause can be anything that
returns a protocol function and it goes through the machinery of record–constructor
descriptors. Now, I want to keep the protocol
stuff because it is standard
and very flexible; but I also want to specify the constructor’s type signature in the
record–type definition.
I could set–up a constructor-signature
clause as follows:
(define-record-type <duo> (fields one two) (protocol (lambda (make-record) (lambda ({A <fixnum>} {B <fixnum>}) (make-record A B)))) (constructor-signature (lambda (<fixnum> <fixnum>) => (<duo>))))
but it would be an ugly duplicate. Should I accept the ugliness?