Previous Next Contents

Classes

Class definitions

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

Class definitions

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.

Type parameters

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.

Class parameters

The parameters class-params are the ones of the object creation function new class-path, as well as the ones of the inheritance construct.

Self and self type binders

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.

Constraints on type parameters

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).

Inheritance

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 variable definition

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

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.

Virtual class

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.

Closed 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

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


Previous Next Contents