class-definition: class-header=
{constraint} {class-fields} class-header: class-tags parameterized-class-name class-params class-binders class-tags: [virtual
] [closed
] parameterized-class-name: class-name |'
ident class-name |(
'
ident {,
'
ident})
class-name class-params: {pattern}+ class-binders: [as
value-name] [:
'
ident] class-fields:inherit
ancestor |val
value |virtual
[protected
] method-type |method
[protected
] method ancestor: [(
typexpr {,
typexpr})
] class-path {expr}+ [as
value-name] value: [private
] [mutable
] inst-var-name [=
expr] method: method-name {pattern}=
expr method-type: method-name:
typexpr
A class definition class
class-definition {and
class-definition}
is recursive. Each class-definition defines a class-name that can be
used in the whole expression except for inheritance. It can also be used for
inheritance, but only in the definitions that follow its own.
A class class-name automatically defines two abbreviations :
class-name and #
class-name. The first one is the type of
objects of this class, while the second is more general as it unifies
with the type of any object belonging to a subclass (see
section 5.5).
The class type parameters correspond to the ones of these two abbreviations. They must be bound to actual types in the class definition using type constraints. So that the abbreviations are well-formed, type variables of the inferred type of the class must either be type parameters or be bound in the constraint clause.
The parameters class-params are the ones of the object creation
function new
class-path, as well as the ones of the inheritance
construct.
The binders class-binders, i.e. as
value-name and :
'
ident,
allow
to bind self (the current object) and its type, respectively. The variable
value-name can then be used as any variable in method body.
The construct constraint
'
ident =
typexpr allows to
specify type parameters. The value of the type parameter ident
will be an instance of typexpr (more precisely, ident and
typexpr are unified).
The inheritance construct
inherit
[(
typexpr {,
typexpr} )
] class-path {expr}+
allows to reuse methods from other classes. It adds the instance
variables and methods from class class-path into the current class,
possibly overriding previously defined ones of the same name. Parent instance variables are initialized with parent class parameters
bound to the arguments {expr}+. Parent type parameters are unified
with type arguments typexpr1,...,typexprn.
An ancestor can be bound by prepending the construct as
value-name
to the inheritance construct above. value-name is not a true
variable and can only be used to select a method, i.e. in an expression
value-name #
method-name. This gives access to the
method method-name as it was defined in the parent class even if it is
redefined in the current class.
Instance variables can be defined or their status can be changed using the
construct val
value.
The definition val
[private
] [mutable
] inst-var-name =
expr adds
an instance variable
inst-var-name whose initial value is the value of expression expr.
If the variable was previously defined, its previous initial value is
overridden.
By default, this variable is visible in subclasses of current class.
The flag private
makes this variable only
visible in the current class.
The flag mutable
allows physical modification of this variable by
methods.
The construct val
[private
] [mutable
] inst-var-name enables to
change the variable status (makes it private and/or mutable), while
keeping the same initial value.
Method definition is written method
method. The definition of a
method overrides any previous definition of this method. The method
will be public (that is, not protected) if any of the definition
states so.
A protected method, method protected
method or virtual
protected
method, is a method that can only be invoked on self
(from other methods of the current class as well as of subclasses of the
current class).
This invocation is performed using the
expression value-name #
method-name, where value-name is
directly bound to self at the beginning of the class definition.
Protected methods do not appear in object types.
Method bodies do not have access to class parameters, but to instance variables. Some special expressions are available in method bodies for manipulating instance variables and duplicating self:
expr: ... | inst-var-name | inst-var-name<-
expr |{<
[inst-var-name=
expr {;
inst-var-name=
expr}]>}
The expression inst-var-name evaluates to the value of the
corresponding instance variable in the current object, while the
expression inst-var-name <-
expr modifies in-place the current
object by replacing the value associated to inst-var-name by the
value of expr. Of course, this instance variable must have been declared
mutable.
The expression
{<
[inst-var-name =
expr {;
inst-var-name =
expr}] >}
evaluates to a copy of the current object in which the values of
instance variables inst-var-name1,...,inst-var-namen have
been replaced by the values of the corresponding expressions expr1,...,exprn.
Methods can be declared, without being defined, with the construct
virtual
method-type. Methods that are declared in this way or
applied to self but not actually defined are said to be virtual.
A class must be flagged virtual if one of its methods is virtual.
Objects cannot be created from a virtual class.
A class can be flagged as closed
. A closed class is a class
to which subclasses cannot add methods.
If the compiler complains that a class must be closed, this usually
means that the type of self has been unintentionally unified with a
closed object type.
Class types are specifications for class definitions. The syntax of class types is closely modeled on class definitions.
The type of a concrete method can be omitted. That way, the status of a method can be changed from virtual to concrete without having the method type be given.
Some type information can be hidden in a class type: instance variables and protected concrete methods can be omitted; previously non-mutable instance variables can be flagged mutable.
class-type: class-type-header=
{constraint} {class-type-fields} class-type-header: class-tags parameterized-class-name class-type-params [:
'
ident] class-type-params: {(
typexpr)
}+ class-type-fields:inherit
ancestor-type |val
value-type |virtual
[protected
] method-type |method
[protected
] method-name [:
typexpr] ancestor-type: [(
typexpr {,
typexpr})
] class-path value-type: [private
] [mutable
] inst-var-name [:
typexpr] method-type: method-name:
typexpr