06-classes
Chapter 6: Classes
A class is a form of type, common in object-oriented programming. Values
called instances can be created from a (non-abstract) class; an instance x
created from class X satisfies the relation x is X.
Classes can also relate via subtyping. If a class Y is declared a subclass of
a class X (that is, Y <: X), then y is Y implies y is X.
Parts of the class declaration's body are called class members, and are
either fields or methods. A field represents data kept within an instance.
A method represents a callable behavior of an instance. A method is like a
function, except that its body also binds the identifier self to the instance
on which the method was called.
6.1 Class declarations
<class-declaration> ::= "class"
<identifier>
("[" <type-parameter-list> "]")?
("<:" <type>)?
<class-body>
<semicolon>
<class-body> ::= "{" <class-member>* "}"
<class-member> ::= <field>
| <method>6.2 The @abstract annotation
An @abstract annotation on a class declaration means that the class cannot
be instantiated. The generated constructor throws an exception when called.
6.3 Fields
A field represents an internal variable of a class, and data particular to instances of that class.
<field> ::= "has"
<identifier>
"?"?
(":" <type>)?
("=" <expression>)?
<semicolon>6.4 The @getter annotation
By default, fields are internal and not accessible for reading outside of the
instance in which they are held. A @getter annotation ensures this access,
providing a zero-parameter method (of the same name as the field) which returns
the value of the field. The return type of the method is the same as the
declared type of the field, if any.
The @getter annotation optionally takes a single parameter in the form of an
identifier; if provided, this identifier is used for the method name instead of
the field name.
A method may not be declared in the class body with the same name as the one
provided (by default or explicitly) by the @getter annotation; doing so
counts as a duplicate declaration, and is signaled as a compile-time error.
6.5 The @setter annotation
By default, fields are internal and not accessible for writing outside of the
instance in which they are held. A @setter annotation ensures this access,
providing a one-parameter method (of the same name as the field), which
returns the value of the parameter. The type of both the paramter and the
return value of the method is the same as the declared type of the field, if
any. The body of the method assigns the value of the parameter to the field.
The @setter annotation optionally takes a single parameter in the form of an
identifier; if provided, this identifier is used for the method name instead of
the field name.
A method may not be declared in the class body with the same name as the one
provided (by defulat or explicitly) by the @setter annotation; doing so
counts as a duplicate declaration, and is signaled as a compile-time error.
However, annotating a field with both @getter and @setter is explicitly
allowed, and creates a single method which is able to both return the value
bound by a field, and set the field's value from a provided argument.
6.6 The @required and @optional annotations
A field is required by default, which means that the class's constructor has
a required named parameter for the field. A @required annotation reaffirms
this, but is essentially a no-op.
Either of the following two are equivalent: an @optional annotation on a
field, or a ? modifier on the field. These mean that the class's constructor
has an optional named parameter for the field. A field whose value is not
passed via the named parameter in its constructor is instead initialized via
the value provided via its @default or @builder annotation (which see), or
none if no such annotations are present. The presence of either @default or
a @builder annotation means the field is optional.
6.7 The @default annotation
A @default annotation expects a single argument, which is parsed as an
expression. A field not initialized via the corresponding named parameter to
the constructor, is instead initialized by evaluating this expression. The
expression is evaluated in a context where self is bound to the instance
being constructed.
A @default annotation on a field is compatible with an @optional
annotation, but not with a @required annotation. Using @default and
@required together signals a compile error.
6.8 The @builder annotation
A @builder annotation expects a single argument, an identifier which resolves
to a method available in the class. A field not initialized via the
corresponding named parameter to the constructor, is instead initialized by
calling this method. The method needs to accept zero arguments; referencing a
method which does not accept zero arguments signals a compile error.
A @builder annotation on a field is compatible with an @optional
annotation, but not with a @required annotation. Using @builder and
@required together signals a compile error.
A @builder annotation is incompatible with a @default annotation, and using
these two together signals a compile error.
6.9 The @type annotation
6.10 The @lazy annotation
6.11 Methods
<method> ::= "method"
<identifier>
("[" <type-parameter-list> "]")?
"(" <parameter-list> ")"
(":" <type>)?
<block>
<semicolon>The self identifier is bound both in the parameter list (available in any
default expressions) and in the method body. In this scope, the self
identifier is bound to the instance on which the method was called.