Declarations
Constructors
Declare constructors with new, select among them by label and argument types, call base constructors, and construct classes that declare none.
since 0.1.0-alpha.1linuxwindowswasm
Description
A constructor is a member introduced by new. There is no new at a call site: you construct an
object by calling the type, Point(3, 4).
new ClassName() { ... } // 'new' marks a constructor
new AnyLabel(string s) { ... } // the name is only a selection label
new Configured(int port = 80) { ... } // constant default parameter value
The name after new is a label. A constructor whose label is the class name is called as
ClassName(args). A constructor with any other label is called as ClassName::label(args), which
is how a class offers several named ways to build the same type. The call picks among the
constructors that share the label by the types of the arguments. Constructor arguments may be named,
and parameters may have constant defaults. A constructor body is one statement, like any other body.
Inside a constructor, Base::Base(args) runs a base class's constructor on this. The derived
class decides when it runs and with which arguments.
Labels, defaults, generics and base constructors
class Point {
int x;
int y;
new Point() { x = 0; y = 0; }
new Point(int px, int py) { x = px; y = py; }
new polar(int r) { x = r; y = 0; }
new origin() { x = 0; y = 0; }
}
console.writeln(Point().x);
console.writeln(Point(3, 4).y);
console.writeln(Point::polar(9).x);
Point o = Point::origin();
console.writeln(o.y);
class Configured {
int port;
string host;
new Configured(int port = 80, string host = "localhost") {
this.port = port;
this.host = host;
}
}
Configured c = Configured(host: "example.org");
console.writeln(c.host + ":" + c.port.toString());
class Box<T> {
T value;
new From(T v) { value = v; }
}
Box<int> b = Box::From::<int>(1);
console.writeln(b.value);
class Animal {
string name;
new Animal(string n) { name = n; }
}
class Dog : Animal {
int tricks;
new Dog(string n, int t) {
Animal::Animal(n);
tricks = t;
}
}
Dog d = Dog("Rex", 3);
console.writeln(d.name + " " + d.tricks.toString());
0
4
9
0
example.org:80
1
Rex 3
Rules
- A constructor is declared with
new Label(params) body. The body is one statement. - Calls select the label by name and then the overload by argument types (most specific wins;
among equals the first declared wins; see
lang.argument-binding). ClassName(args)selects constructors labeled with the class name.ClassName::label(args)selects those with that label. A qualified class name works the same way:NS::Class::label(args).- For a generic class the type arguments come, in order, from an explicit tuple, from an enclosing
target type, and from the constructor arguments. An explicit tuple follows the complete label:
Box::From::<int>(1). - Constructor parameters may be named at the call and may have constant defaults.
Base::Base(args)inside a constructor runs a base constructor. The derived constructor controls the order.- A class that declares no constructor can still be constructed.
ClassName(a, b, ...)fills the data fields in declaration order; fields of a base class come first. Fewer arguments than fields leave the remaining fields at their defaults, and no arguments is ordinary default construction. - Passing more arguments than the class has data fields is a compile error ("too many arguments to
construct"). A primitive has no data fields, so
int(x),string(x)andbool(x)are errors; use conversion methods such asx.toInt()instead. - A constructor may assign a
readonlyfield of its own class (seelang.readonly), but not aconstfield. - There is no
statickeyword. A function that builds an instance is written as a labeled constructor.
Examples
A class with no constructor is built from its fields in order:
Memberwise construction
class Base { string a; }
class Derived : Base { int b; }
Derived d = Derived("x", 2);
console.writeln(d.a + d.b.toString());
class FieldError { string field; string message; int code; }
FieldError e = FieldError("email", "required");
console.writeln(e.field + ":" + e.message + ":" + e.code.toString());
FieldError z = FieldError();
console.writeln("[" + z.field + "]");
x2
email:required:0
[]
Constructors are chosen by argument type:
Overloaded constructors
class P {
int x;
new P(int a) { x = a; }
new P(string s) { x = s.length(); }
new P(float f) { x = 100; }
}
console.writeln(P(5).x);
console.writeln(P("abc").x);
console.writeln(P(1.5).x);
5
3
100
Too many arguments are rejected:
Too many arguments
class FieldError { string field; string message; }
FieldError e = FieldError("a", "b", "c");
// error: too many arguments to construct 'FieldError': it has 2 assignable fields but 3 were given
int x = int(3);
// error: too many arguments to construct 'int': it has 0 assignable fields but 1 were given
See also
- Classes — Declare reference types with fields, methods, constructors and accessors, with generics and inheritance from one or more base classes.
- readonly fields — Fix an instance field once, either in its initializer or in every constructor, and keep it read-only afterwards.
- Argument binding — How a call's arguments are matched to parameters, filled by defaults or injection, and how overloads are ranked.
- Fields — Declare the data a class or struct holds, with optional initializers, and how a field without an initializer gets its default value.