Constructors are special methods, and they are used for creating instances for a given type.
Freya is a language with anonymous constructors: all constructors either are named as the containing class, or they have no name at all. They are declared using the constructor keyword instead of method, and they never have a return type.
Stack = class[X] public constructor(Capacity: Integer); constructor; // ... end;
Constructors behave very differently from methods regarding inheritance. A derived class inherits the constructors implementation from it immediate ancestor: the inherited implementation can be executed by constructors in the derived classes. However, these inherited constructors are not considered as members of the derived class. A derived class must always declare its own constructors, or accept the default parameterless constructor generated by the compiler for types with no explicitly declared constructors.
Every constructor must start its execution by calling a constructor from its parent class, or a sibling constructor, defined in the same class. However, this call can be omitted, and in that case, the compiler assumes you're calling a parameterless constructor from the parent class.
This is one of the constructors declared for the Stack class:
implementation for Stack[X] is var Items: Array[X]; constructor(Capacity: Integer); begin Self.Items := new Array[X](Capacity); end;
There's no explicit call to any constructor from the base class. As said before, the compiler assumes a call to the parameterless constructor from the base class, in this case, System.Object:
implementation for Stack[X] is var Items: Array[X]; // Parenthesis after Inherited are optional. constructor(Capacity: Integer) : Inherited(); begin Self.Items := new Array[X](Capacity); end;
Please, note that the call to the parent constructor must be written before the begin keyword from the statement block. Since we were calling the parent constructor, we have used the Inherited predefined identifier. If you must call a sibling constructor, you must use the Self predefined identifier:
constructor: Self(128); begin end;
In this case, we have passed a parameter to the sibling constructor.
Freya does not support default parameters: we thought that mixing default parameters and overloading was a risky business. Nevertheless, default parameters can be simulated by method overloading. When it comes to constructors, Freya may help with the implementation.
This code fragment shows a class with three public constructors:
Plastic = sealed class(IMaterial) public constructor(Color: Pixel; Reflection, PhongAmount, PhongSize: Double); constructor(Color: Pixel; Reflection: Double); constructor(Color: Pixel); // More declarations... end;
The most general constructor is the first, and the other two constructors simply drop a parameter from the list. Now we can mix inline implementation and constructor chaining this way:
Plastic = sealed class(IMaterial) public constructor(Color: Pixel; Reflection, PhongAmount, PhongSize: Double); constructor(Color: Pixel; Reflection: Double); : Self(Color, Reflection, 0.0, 1.0); constructor(Color: Pixel); : Self(Color, 0.0, 0.0, 1.0); // More declarations... end;
In our example, the second and third constructors are implemented by delegating the initialization to their big brother and, since no further instructions, are required, we have dropped the statement block from the implementation. The good thing about this technique is that you know the values for the omitted parameters in a glance.
You can also omit the statement block for a chained constructor inside an implementation section.
Static constructors, also known as type initializers, may be used to initialize the static fields in a class or record. A static constructor is never declared with the type, and they must be directly included in the corresponding implementation section:
SillyClass = class public static property Randomizer: System.Random; readonly; end; implementation for SillyClass is static constructor; begin Randomizer := new Random; repeat until Randomizer.Next(10) > 5; end; end.
Note that, in most of the cases, you can achieve the same result using static field initializers. A static property can have an initializer when it has an automatic field-based implementation, as in the previous example.
The Freya Programming Language
Type declarations
Type members
Destructors
Methods
User defined operators
Fields
Properties
Indexers
Events
Instantiation