Next: friends, Previous: interfaces, Up: Top [Contents][Index]
Labels are types built on top of other types: we put label–types on values of a parent type to handle them locally in a special way. There are two kinds of labels:
The following syntactic bindings are exported by the library
(vicare language-extensions labels)
. All the auxiliary syntaxes
are exported by the library (vicare)
and reexported by the
library (vicare language-extensions labels)
.
Define a new label type. ?type-name must be a syntactic identifier representing the label name.
The clause parent
is mandatory and its single argument must be
a type annotation.
The following clauses can be used in the same way they are used in
define-record-type
:
parent type-predicate equality-predicate comparison-procedure hash-function method mixins
notice that labels cannot implement interfaces.
The clause constructor
may appear zero, one or more times;
these clauses define a constructor function to be used with the syntax
new
. The constructor
clause has a syntax similar to
lambda/checked
; it must have the format:
(constructor ?typed-formals ?body0 ?body ...)
?typed-formals must not specify a return value: the constructor returns a single value of type type-name, and its specification is automatically generated.
The clause destructor
may appear zero or one time; this clause
defines a destructor function to be used with the syntax
delete
; this destructor is not used by the garbage
collector. The destructor
clause has a syntax similar to
lambda
; it must have the format:
(destructor ?formals ?body0 ?body ...)
where ?formals must specify a single argument of type ?type-name. ?formals must not specify a return value: the destructor should return unspecified values.
The optional clause nongenerative
must be used with a single
argument being a symbol representing a UID associated with the label
type; such symbol is used by type-unique-identifiers
and so it
allows multimethods to use label types.
The following example defines a label <String>
that is just a
synonym for <string>
:
(define-label-type <String> (parent <string>)) (define {O <String>} "ciao") (.length O) ⇒ 4 (hash O) → (string-hash O)
The following example defines a label to represent fixnums returned by comparison procedures (‘-1’, ‘0’, ‘+1’):
(define-label-type <comparison-fixnum> (parent (or <non-negative-fixnum> <negative-fixnum>)) (type-predicate (lambda ({parent-pred <type-predicate>}) (lambda (obj) (and (parent-pred obj) (fx<=? obj +1) (fx>=? obj -1)))))) (is-a? +1 <comparison-fixnum>) ⇒ #t (is-a? -1 <comparison-fixnum>) ⇒ #t (is-a? 0 <comparison-fixnum>) ⇒ #t (is-a? +2 <comparison-fixnum>) ⇒ #f (is-a? -2 <comparison-fixnum>) ⇒ #f
Now let’s define a custom hash function (we ignore the parent hash function that gets passed as parent-hash argument):
(define-label-type <String> (parent <string>) (hash-function (lambda (parent-hash) (lambda (S) (if (string-empty? S) 0 (char-hash (string-ref S 0))))))) (define {O <String>} "ciao") (hash O) ≡ (char-hash #\c)
Let’s define a label with a method to increment a fixnum.
(define-label-type <fx> (parent <fixnum>) (method (incr) (fxadd1 this))) (define {O <fx>} 10) (.incr O) ⇒ 11
Now let’s define a method for adding prefixes and suffixes:
(define-label-type <String> (parent <string>) (method ({append <String>} {suff <String>}) (string-append this suff)) (method ({append <String>} {pref <String>} {suff <String>}) (string-append pref this suff))) (define {O <String>} "ciao") (.append O "-suff") ⇒ "ciao-suff" (.append O "pref-" "-suff") ⇒ "pref-ciao-suff" (.length (.append O "pref-" "-suff")) ⇒ 14
In the following example:
(define-label-type <vec> (parent <nevector>) (constructor (a b) (vector a b)) (constructor (a b c) (vector a b c))) (new <vec> 1 2) ⇒ #(1 2) (new <vec> 1 2 3) ⇒ #(1 2 3)
we can think of the constructor
clauses as generating the
following functions definition:
(define/overload ({<vec>-constructor <vec>} a b) (vector a b)) (define/overload ({<vec>-constructor <vec>} a b c) (vector a b c))
notice that a type signature for the return value has been automatically inserted.
Here we define a bogus destructor function:
(define-label-type <vec> (parent <vector>) (destructor ({O <vec>}) `(deleted ,O))) (define {O <vec>} '#(1 2)) (delete O) ⇒ (deleted #(1 2))
we can think of the destructor
clauses as generating the
following function definition:
(define (<vec>-destructor {O <vec>}) `(deleted ,O))
Here we show how to include mixin clauses in a label definition:
(define-mixin-type <stuff> (method (pussy) (list 'pussy (.name this)))) (define-label-type <peluche> (parent (list <symbol>)) (method (name) (car this)) (mixins <stuff>)) (define {O <peluche>} '(cat)) (.name O) ⇒ cat (.pussy O) ⇒ (pussy cat)
Next: friends, Previous: interfaces, Up: Top [Contents][Index]