More work in the ‘typed-language’ branch of Vicare, for both the expander and the built–in types infrastructure. Some more type propagation stuff is implemented for built–in primitives.
Everything I discuss here is relative to code in the head of the ‘typed-language’ branch.
Since some commits ago I started adding new command line options to enable/disable warnings at expand–time. I want Vicare’s command line interface to feel like the GCC’s one, so there is a command line option -Wall that will enable all the warnings. Here some other options:
Enable or disable raising a &warning
exception when an operand in a logic
expression (if
test, and
, or
, et cetera) always returns
false or non–false. By default this warning is disabled. As example, the following
code:
(and #t (read))
will cause the following warning at expand–time:
*** Vicare: warning: Condition components: 1. &expand-time-type-signature-warning 2. &who: and 3. &message: "expression used as operand in logic predicate is \ typed as always returning non-false" 4. &syntax: form: #[syntax expr=(and #t (read)) line=8 column=3 source="demo.sps"] subform: #[syntax expr=#t line=8 column=9 source="demo.sps"] 5. &type-signature: #[signature (<true>)]
Enable or disable raising a &warning
exception when an operand evaluated
for its return values is typed as not returning. By default this warning is
disabled. As example, the following code:
(define (operand) (error #f "bad behaviour")) (define (operator rand) (display rand)) (operator (operand))
will cause the following warning at expand–time:
*** Vicare: warning: Condition components: 1. &expand-time-type-signature-warning 2. &who: chi-closure-object-application 3. &message: "expression used as operand in procedure application \ is typed as not returning" 4. &syntax: form: #[syntax expr=(operator (operand)) line=15 column=3 source="demo.sps"] subform: #[syntax expr=(operand) line=15 column=13 source="demo.sps"] 5. &application-operand-signature: #[signature <no-return>]
Enable or disable raising a &warning
exception when a local lexical
variable is defined but never used. By default this warning is disabled. As
example, the following code:
(let ((a 1) (b 2) (c 3)) (list a c))
will cause the following warning at expand–time:
*** Vicare: warning: Condition components: 1. &warning-unused-lexical-variable 2. &who: let/checked 3. &message: "unused lexical syntactic binding" 4. &syntactic-identifier: #[id b line=9 column=10 source="demo.sps"]
We need to know that a &warning
exception will not stop expansion and
compilation, but we must handle it correctly when, for example, we expand code using
eval
; this is a way of doing it:
(with-exception-handler (lambda (E) (unless (warning? E) (raise-continuable E))) (lambda () (eval ?sexp ?env)))
Should eval
block &warning
exceptions automatically? With a
configurable run–time option? Maybe. And maybe, in future, it will.
Overloaded functions are an expand–time aggregation of functions linked to the same name and having different number and type of arguments. For example, in the code:
(define/overload (fun {O <fixnum>}) (list 'fixnum O)) (define/overload (fun {O <string>}) (list 'string O)) (define/overload (fun {A <vector>} {B <vector>}) (list 'vectors (vector-append A B))) (fun 123) ⇒ (fixnum 123) (fun "ciao") ⇒ (string "ciao") (fun '#(1) '#(2)) ⇒ (vectors #(1 2))
an overloaded function named fun
is defined by the first use of
define/overload
; subsequent uses add new specialisations to the same
function. We can use overloaded functions only with the “canonical” function
application syntax:
(?fun ?operand ...)
using apply
will cause an expand–time syntax violation.
Overloaded functions are also partially supported by records, using the
method/overload
clause:
(define-record-type <duo> (fields one two) (method/overload (doit {O <duo>}) (+ (.one O) (.two O))) (method/overload (doit {O <duo>} {C <number>}) (* C (+ (.one O) (.two O))))) (define O (new <duo> 1 2)) (.doit O) ⇒ 1 (.doit O 3) ⇒ 9
Being an expand–time thing: overloaded methods are not available for late binding; that is why support is only partial. This is an important limitation: it makes it harder to implement interfaces (which will require late binding).
At present, only a basic implementation of overloaded functions is available. There are two main reasons:
Now, Vicare already has some sort of solution for these problems: it is
implemented by multimethods from the library (vicare language-extensions
multimethods)
. There are problems though:
or
,
and
, not
, et cetera cannot be used.
Solving these problems is one of the things I think of these days…