Constructors
From RemObjects Software
This is a Oxygene Language Feature topic
Feel free to add your notes to this topic below.
Constructors (or in short: ".ctors") are special methods that are used to create and initialize instances of a class.
.NET does not provide the concept of individual names for constructors, so Oxygene uses unnamed constructors.
You can create several overloaded constructors that expect different parameters and your constructors can call each other to defer parts of the initialization:
type MyClass = class public constructor; constructor(aValue: String); end; ... constructor MyClass; begin ... // instance initialization goes here. end; constructor MyClass(aValue: String); begin constructor; // call other constructor ... // initialization based on aValue. end;
constructors are called by using the the new keyword with the class type name:
lClass := new MyClass();
Any parameters expected by one of the constructors can be passed as part of the invocation:
lClass := MyClass.Create('hello'); lClass := new MyClass('hello again');
Note the use of 'Create' above. This is the equivalent of 'new' and is provided for backward compatibility only (see Project Options - Compatibility).
Class Constructors
In addition to constructors for class instances, you can also provide a "class constructor" implementation, which will be called by the framework the first time your class is ever accessed.
In contrast to instance constructors, you can only provide one non-overloaded and parameter-less class constructor. You will never call these explicitly (can't, in fact), but the runtime will call them for you.
class constructor MyClass; begin ... // class initialization goes here. end;
Constructors and Inheritance
When creating new descendant classes in Oxygene, the compiler will automatically make all (non-private) constructors implemented in the base class available for the new class.
This is in contrast to C#, where a descendant class will need to re-implement all relevant constructors - even if they would just be empty and call the inherited version; in Oxygene, this is not necessary.
Once you start implementing one or more custom constructors for your descendant class (whether replacing an existing one or adding a newly overloaded one), the compiler will no longer make the base constructors available.
The reasoning behind this is that if one or more custom constructor implementations are present, it is safe to assume that none of the remaining base constructors are sufficient to properly construct and initialize the class. For example, EOIDError might depend on the ID and on code that gets executed in your new constructor, but if the base constructor was also available, callers could completely circumvent your own constructor logic. If this weren't done, you would be stuck with the constructors defined in your base class, and never ever be able to get rid of them.
Calling other constructors
In your constructor implementation, you must call an inherited constructor (or another constructor that calls an inherited constructor) before you can access members of your class. However, if there's a MATCHING constructor in the base class, Oxygene will call that automatically for you when no explicit constructor calls are made.
Extended Constructor Calls
Very often the first thing to be done after creating a class is to initialize some of its fields and properties. For example:
with p := new Point(param1, param1) do begin p.x := 10; p.y := 20; // other code end;
Oxygene allows you to add named parameters after the normal constructor parameters. These are in the form name := value thus allowing the code above to be replaced by:
with p := new Point(param1, param1, x := 10, y := 20) do begin // code end;
This extended syntax is only supported for constructors and the named parameters can only be placed after the normal parameters.
Field Initialization
The time that a constructor initializes its fields is important and this can occur before or after the call to an inherited constructor.
Fields are normally initialized before calling the inherited constructor, but with the following three exceptions when the field:
- uses SELF directly
- accesses field(s) of the ancestor class
- calls a method of the current class
Consider the following code:
type Foo = class private Field1: string := 'hello'; Field2: &Type := self.GetType(); public constructor; end; implementation constructor Foo; begin // Field1 will be initialized here Console.WriteLine(Field1); Console.WriteLine(Field2.Name); // error inherited constructor; // Field2 will be initialized here Console.WriteLine(Field2.Name); end;
Because Field2 uses "self" in its initialization, it cannot be initialized until after the base constructor was run. Field1 doesn't rely on self, so it will be initialized at the beginning and is accessible from the start.
Notes
For backward compatibility, you can use the keyword "Create" as a standard name for constructor methods. You have to enable this option in the Project Options, see Legacy Create Constructors.
type MyClass = class public constructor Create; end; ... constructor MyClass.Create; begin ... // instance initialization goes here. end;
Examples
Example 1
type ClassA = public class public constructor(); constructor(aValue: String); end; ClassB = public class(ClassA) end;
Because ClassB doesn't implement any constructors of its own, both constructors from ClassA are made available and the following are both valid:
myObject := new ClassB; // ok myObject := new ClassB('hello'); // ok
Example 2
type ClassC = public class(ClassA) constructor(aValue: Int32); constructor(aValue: Char); end;
ClassC implements its own constructors, so only these are available:
myObject := new ClassC; // error myObject := new ClassC('hello'); // error myObject := new ClassC(5); // ok myObject := new ClassC('a'); // ok
Example 3
Your class defines two constructors and you want to call one from the other
without using the old "create" syntax. You can now write:
constructor MyClass(A: Integer); begin inherited constructor(); fA := A; end; constructor MyClass(A: Integer; B: String); begin constructor(A); fB := B; end;
See Also
Product: RemObjects Oxygene (formerly known as Chrome)
Current version: 3.0
Previous Versions: 'Joyride' (2.0), 'Floorshow' (1.5), 'Adrenochrome' (1.0)
Glossary — Keywords — Language Features — Platform Features — Samples — Articles — How To — Issues
