Constructors
A constructor is a function that builds a value of its type. It is declared in the type's extend block with the type's own name, takes no receiver, and returns exactly the type. It is called by the type's name, like a function: Time(9, 30).
constructor = [ "pub" ] "func" TypeName "(" [ parameters ] ")" "->" TypeName block // inside extend TypeName
struct Time {
hours: int;
minutes: int;
}
extend Time {
func Time() -> Time {
return Time { hours: 0, minutes: 0 };
}
func Time(totalMinutes: int) -> Time {
let inDay = totalMinutes % (24 * 60);
return Time { hours: inDay / 60, minutes: inDay % 60 };
}
func Time(hours: int, minutes: int) -> Time {
return Time(hours * 60 + minutes);
}
}
func Main() -> int {
let start = Time(7, 95); // 8:35
let later = Time(start.hours * 60 + start.minutes + 135); // 10:50
var midnight: Time; // Time() — 0:00
return 0;
}
A constructor ends by building the value itself — usually with a struct literal or by calling another constructor. It does not replace literals; it decides what goes into one, so a rule such as "minutes are below 60" is written once instead of at every literal.
| Kind of function | Name | First parameter | Called as |
|---|---|---|---|
| Method | anything | self: &Time, &var Time or Time | start.Show() |
| Static function | anything but Time | not self | Time::Midnight() |
| Constructor | Time, always | not self | Time(9, 30) |
Overloads
A type may have any number of constructors, told apart by their parameters like any overload set. Above, the two-argument constructor converts to minutes and passes the total to the one-argument constructor, so the wrapping past midnight is written once.
A call with arguments that no constructor takes is an error naming the candidates, such as call to 'Time' expects 2 arguments, but 1 was provided when only the two-argument constructor exists.
Default construction
var value: T; with no initializer calls T() when the type has a constructor that can be called without arguments:
var midnight: Time; // runs Time()
With no such constructor the declaration is still allowed, but it leaves the storage uninitialized, and the compiler refuses to read it before it has been assigned:
error: variable 'q' is used before it is initialized
See Initialization for how such a local becomes initialized, field by field or as a whole. If more than one constructor can be called with no arguments — Time() and Time(hours: int = 0) — the declaration is ambiguous:
error: default construction of 'Time' is ambiguous
note: more than one constructor can be called without arguments
help: remove defaults so exactly one constructor accepts no arguments
Generic types
A generic type's constructor is declared in its generic extend block and called with the type arguments written out:
struct Pair<T> {
first: T;
second: T;
}
extend Pair<T> {
func Pair(both: T) -> Pair<T> {
return Pair<T> { first: both, second: both };
}
}
let twins = Pair<int>(7);
A convenience, not a lock
A type with constructors can still be built with a literal wherever its fields are visible, so a constructor's rules can be bypassed inside its package. Making the fields private to the package, and the constructor pub, leaves other packages only the constructor; see Visibility.
Rules and errors
| Mistake | Error |
|---|---|
| Calling a type that has no constructor | type 'Point' cannot be called because it has no declared constructor |
Declaring the constructor outside extend | name 'Time' cannot be declared as a function because it is already a type in this scope |
| A result other than the type | constructor 'Time' must return exactly 'Time' |
Two constructors callable with no arguments, and var t: Time; | default construction of 'Time' is ambiguous |
The first error's help names both ways out: declare a receiverless constructor in its extend block or use explicit initialization.
A function that can fail to build its value — one returning T? or T ! E — is not a constructor; give it a descriptive name and declare it as a static function, called as T::Parse(…).
See also
- Structs — struct literals
- Methods — the
extendblock - Destructors — the other end of a value's life
- Learn: Constructor, Initialization