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]