Mapped Types
Mapped Types are a unique feature of the Elements compiler that let you create compatibility wrappers for types without ending up with classes that contain the real type. The wrappers will be eliminated by the compiler and rewritten to use the type the mapping maps to.
Note: When working with Oxygene, you will most commonly use mapped types (for example as provided by the Elements RTL cross-platform library). Using mapped types is seamless, and they behave just like regular non-mapped types.
You will not often need to implement mapped types yourself, but for when you do, Oxygene – like RemObjects C#, Swift and Java – provides a syntax for implementing mapped types when needed, with the mapped
keyword.
Please refer to the Mapped Types topic in the Language Concepts section for more details.
A mapped type can be a Class or a Record, and is declared like any other class or record, but with the mapped to
keywords following the declaration, alongside of the type that is being mapped – also referred to as the "original type".
type
MyString = public class mapped to String
end;
Mapped Classes can optionally provide an ancestor, as long as that ancestor is either also an ancestor of the original class, or is in itself a mapped class, mapped to an ancestor of or directly to the original class. Both mapped classes and mapped records can provide an optional list of Interfaces that they adhere to.
Members
Mapped types can define members such as Constants and Properties, as well as actions that work with that data (Methods), just like regular classes and records. However, because at runtime mapped classes are, well, mapped to a different, existing class, mapped types cannot add Fields, or properties with implicit storage (which would require an implicit field to be added).
Inside the code of the members of a mapped class (method bodies, property getters and setters), a special mapped
Expression can be used to refer to members of the original type, or the "self" of the original type.
type
MyString = public class mapped to String
property TwiceTheLength: Integer read mapped.Length*2;
end;
Without dereferencing via mapped
, code inside a mapped class sees only the members defined on the mapped class. Members of the original class are available only through mapped
. mapped
can also be used standalone, to refer to the current instance as its original type.
You can think of mapped
as equivalent to self
– both refer to the same physical instance of the type, but they differ in as what type the class or record is seen.
var x := self; // `x` is a `MyString`
var y := mapped; // `y` is a String
if x = y then ... // but they are the same
Shortcut Mappings
For methods, oxygene supports a special syntax for direct one-to-one mappings of members, using the mapped to
Member Modifier:
type
MyString = public class mapped to String
method MakeUpper: Integer; mapped to ToUpper;
end;
Here, the MakeUpper
method is mapped directly to the ToUpper
method of the underlying original class.
Note that while in this example the name of mapped and original member differ, it is also acceptable (and common) to map members with the same name, in order to expose the original member on the mapped type, "as as".
type
MyString = public class mapped to String
method ToUpper: Integer; mapped to ToUpper;
end;
Constructors
Mapped types can provide Constructors that can be used to instantiate copies of the mapped type. Because instantiating a mapped type, ultimately, must end up with instantiating a copy of the original type, constructors in mapped types have some additional capabilities.
In addition to deferring execution to other constructors using regular constructor
Expressions, constructors in mapped types are also allowed to instantiate a copy via any other means (say by calling class factory methods), and returning an instance by assigning to result
or calling exit
.
constructor MyString(aChar: Char);
begin
result := aChar as String;
end;
It is also possible to use the mapped
Expression to defer to constructors of the original type. This works in symmetry with how the inherited constructor
Syntax works in "real" classes:
constructor MyObject;
begin
mapped constructor("Hello");
end;
Type Visibility
Just as with regular Classes and Records, the visibility of a mapped type can be controlled by applying a Visibility Modifier on the declaration. A mapped type cannot be more visible than the underlying original type. The default visibility is assembly
.
Other Modifiers
A mapped type is a Class or Record that is marked with the mapped to
Type Modifier.
See Also
- Mapped Types in the Language Concepts section
mapped to
Member Modifiermapped
Expression- Elements RTL