trait.ss: Object-Oriented Traits
To load: (require (lib "trait.ss"))
A trait is a collection of methods that can be converted to a mixin and then applied to a class. Before a trait is converted to a mixin, the methods of a trait can be individually renamed, and multiple traits can be merged to form a new trait. The trait constructs provided by the trait.ss library work with the classes of the class.ss library (see section 4).
The trait form creates a new trait:
(trait trait-clause ···) trait-clause is one of (public optionally-renamed-id ···) (pubment optionally-renamed-id ···) (public-final optionally-renamed-id ···) (override optionally-renamed-id ···) (overment optionally-renamed-id ···) (override-final optionally-renamed-id ···) (augment optionally-renamed-id ···) (augride optionally-renamed-id ···) (augment-final optionally-renamed-id ···) (inherit optionally-renamed-id ···) (inherit/super optionally-renamed-id ···) (inherit/inner optionally-renamed-id ···) method-definition (field field-declaration ···) (inherit-field optionally-renamed-id ···)
The body of a trait form is similar to the body of a
class form, but restricted to non-private method definitions.
In particular, the grammar of optionally-renamed-id,
method-definition, and field-declaration are the same as
for class (see
section 4), and every method-definition must have a
corresponding declaration (one of public, override,
etc.). As in class, uses of method names in direct calls,
super calls, and inner calls depend on bringing
method names into scope via inherit, inherit/super,
inherit/inner, and other method declarations in the same
trait; an exception, compared to class is that
overment binds a method name only in the corresponding
method, and not in other methods of the same trait. Finally, macros
such as public* and define/public work in trait
as in class.
(trait->mixin trait) converts a trait to a mixin, which can be
applied to a class to produce a new class. An expression of the form
(trait->mixin (trait trait-clause ···))
is equivalent to
(lambda (%) (class % trait-clause ··· (super-new)))
Normally, however, a trait's methods are changed and combined with other traits before converting to a mixin.
(trait-sum trait ···1) produces a trait that combines all of the
methods of the given traits. For example,
(define t1
(trait
(define/public (m1) 1)))
(define t2
(trait
(define/public (m2) 2)))
(define t3 (trait-sum t1 t2))
creates a trait t3 that is equivalent to
(trait (define/public (m1) 1) (define/public (m2) 2))
but t1 and t2 can still be used individually or
combined with other traits.
When traits are combined with trait-sum, the combination
drops inherit, inherit/super, inherit/inner, and inherit-field
declarations when a definition is supplied for the same method or field name by
another trait. The trait-sum operation fails (the
exn:fail:contract exception is raised) if any of the traits to combine define a
method or field with the same name, or if an inherit/super or
inherit/inner declaration to be dropped is inconsistent with the
supplied definition. In other words, declaring a method with
inherit, inherit/super, or inherit/inner,
does not count as defining the method; at the same time, for example,
a trait that contains an inherit/super declaration for a
method m cannot be combinaed with a trait that defines m
as augment, since no class could satisfy the requirements of
both augment and inherit/super when the trait is later
converted to a mixin and applied to a class.
(trait-exclude trait-expr identifier) produces a new trait
that is like the result of trait-expr, but with the definition
of a method named by identifier removed; as the method
definition is removed, either a inherit,
inherit/super, or inherit/inner declaration is
added:
A method declared with
public,pubment, orpublic-finalis replaced with ainheritdeclaration.A method declared with
overrideoroverride-finalis replaced with ainherit/superdeclaration.A method declared with
augment,augride, oraugment-finalis replaced with ainherit/innerdeclaration.A method declared with
overmentis not replaced with anyinheritdeclaration.
If the trait produced by trait-expr has no method definition for
identifier, the exn:fail:contract exception is raised.
(trait-exclude-field trait-expr identifier) produces a new trait
that is like the result of trait-expr, but with the definition
of a field named by identifier removed; as the field
definition is removed, an inherit-field declaration is
added.
(trait-alias trait-expr identifier new-identifier) produces a
new trait that is like the result of trait-expr, but the
definition and declaration of the method named by identifier is
duplicated with the name new-identifier. The consistency
requirements for the resulting trait are the same as for
trait-sum, otherwise the exn:fail:contract exception is raised. This
operation does not rename any other use of identifier, such as
in method calls (even method calls to identifer in the cloned
definition for new-identifier).
(trait-rename trait-expr identifier new-identifier) produces
a new trait that is like the result of trait-expr, but all
definitions and references to methods named identifier are
replaced by definitions and references to methods named by
new-identifier. The consistency requirements for the resulting
trait is the same as for trait-sum, otherwise the
exn:fail:contract exception is raised.
(trait-rename-field trait-expr identifier new-identifier) produces
a new trait that is like the result of trait-expr, but all
definitions and references to fields named identifier are
replaced by definitions and references to fields named by
new-identifier. The consistency requirements for the resulting
trait is the same as for trait-sum, otherwise the
exn:fail:contract exception is raised.
External identifiers in trait, trait-exclude, trait-exclude-field,
trait-alias, trait-rename, and trait-rename-field forms are subject to
binding via define-member-name and
define-local-member-name (see section 4.3.3.3). Although
private methods or fields are not allowed in a trait form,
they can be simulated by using a public or field declaration and a
name whose scope is limited to the trait form.