Class References

A class reference is a special meta type that can be used to refer to classes (not instances of them) within a certain subtree of the class hierarchy. This allows to write code that can work polymorphically with classes – for example dynamically instantiate different subclasses or call virtual static methods.

A class reference can be expressed by using the class of keywords, followed by the name of a Class.

var lControlClass: class of Control;
lControlClass := Button;

A class reference variable can hold a reference to the base type it was defined for (in this example, Control, as well as any subclass of it (e.g. Button)). Assignment can be made by simply specifying the type name, or by using the result of the classOf() System Function.

A valid class reference (i.e. one that is not nil, but references an actual type) can be used in many of the same scenarios that the type name itself can be used. Most interestingly, it can be used in new Expressions, to instantiate instances of the referenced type dynamically.

This is very powerful, as it allows for code that can instantiate new types, without knowing the exact subclass that is being instantiated, at compile time.

A class reference can also be used to call any Static Members of the type.

Of course, since a class reference is strongly-typed to reference a specific base type, it can only provide access to constructors and static members defined on the base type. For example, the above reference would allow calls to constructors and static members declared on Control, but not any new members introduced by Button.

Virtual Constructors and Status Members

When working with class references, Oxygene provides the ability to have Constructors, as well as any static Methods, Properties or Events be Polymorphic by being marked virtual (or abstract) in a base class, and overridden in descendant classes.

Polymorphism will work just as it does normally for class instances: at runtime, calls will be directed to the implementation most appropriate for the current class reference. For example:

type
  Control = public abstract class
  public
    property DescriptionForToolBox: String; static; abstract;
    constructor(aWindow: Window); virtual;
  end;
  
  Button = public class(Control)
    property DescriptionForToolBox: String read 'A Button Control'; static; abstract;
    constructor(aWindow: Window); override;
  end;
  
var ControlType: class of Control := Button;

writeLn(ControlType.DescriptionForToolBox);  // prints `A Button Control`
var c := new ControlType(SomeWindow);        // creates a new button

Implementation Details

Class references in Oxygene are implemented via a meta class type.

Since emitting a meta class for every type would be a big overhead, the compiler automatically decides whether a meta class is required for a given class.

A meta class will be generated if

  • the class (or one of its base classes) is used in a class reference type anywhere in the project
  • the class (or one of its base classes) declares a virtual constructor or a virtual static member.

For this reason, class references can not be used for classes from external references (unless the external reference already provided the meta class). In other words, class of cannot be used with, say, classes provided by the platform.

For custom solutions spread across multiple projects, if project A references project B, then project B can only use class of with types from project A if a class reference for them was declared or used in project A (or if the type has a virtual constructor or a virtual static member).

An easy way to do this is to simply declare a Type Alias in the base project, for the root of the type hierarchy that should be enabled for class references, eg:

type
  Control = public abstract class
  end;

  ControlClass = public class of Control;

The type alias ensures that Control, and all its subclasses, will be ready for use with class references (even if the rest of the project that declares Control does not use class references.

Special Members on Meta Classes

Classes references implement a couple of helper methods

  • Instance: class of   ClassName — Holds the instance of this meta class.
  • ActualType: &Type — returns the platform type for the class this meta class refers to (Type on .NET, Java and Island, and Class on Cocoa).

Additionally, any class that a meta class was generated for will expose a GetMetaClass instance method that returns the meta class for a live instance.

See Also