Oxygene (programming language)

From Seo Wiki - Search Engine Optimization and Programming Languages

Jump to: navigation, search
Developer RemObjects Software
Stable release 3.0.21 (August 29, 2009; 140926681 ago)
Influenced by Object Pascal, C#
OS Common Language Infrastructure
License Commercial
Website Oxygene Homepage

Oxygene (formerly known as Chrome) is a programming language developed by RemObjects Software for the Common Language Infrastructure. Oxygene is Object Pascal-based. Compared to the now deprecated Delphi.NET, Oxygene does not emphasize total backward compatibility, but is designed to be a full .NET citizen and leverage all the features and technologies provided by the .NET runtime.

Starting 2008, RemObjects Software has licensed its compiler and IDE technology to Embarcadero to be used in their Delphi Prism product.[1] Delphi Prism offers full integration into Visual Studio 2005/2008. If the user doesn't have Visual Studio installed, Oxygene's setup includes the Visual Studio 2008 Shell.

Oxygene Language

The Oxygene language has its origins in Object Pascal in general and Delphi in special, but was designed to reflect the guidelines of .NET programming and to create fully CLR-compliant assemblies. Therefore not all language features known from Object Pascal / Delphi can be found any longer in Oxygene or only as legacy features.


String Literals

String literals can be written with single- or double-quotes. Single-quoted strings have to contain more than one character, otherwise they're treated as character literals. Double-quoted strings can span multiple lines, the line breaks will be part of the string value.

var a := 'a'; //char
var b := "a"; //string
var c := 'ab'; //string
var d := "line

Character Literals

Character literals can be written as single-quoted letters, or using there character number prepended by a "#".

Integer Literals

Integer literals can be written as "normal" decimal numbers, as hexadecimal numbers (prependend with a "$") or as binary numbers (prepended with a "%").

//All variables have the same value:
var a := 16;
var b := $10;
var c := %10000;

Floating Point Literals

By default every floating point literal that has no other type information connected to it, is treated as double. Floating point literals are written as digits, followed by the period as decimal separator and then another sequence of digits. A syntax for exponential write is supported: 31.415926E-1


Identifiers in Oxygene consist of unicode letters. It must not start with a digit, but may contain them. The underscore "_" is allowed at the beginning and inside an indentifier. Keywords can be used as identifiers, if they are escaped with an ampersand "&". A "Special Identifier Syntax" can be used, to use any character in an idenitifer-name[2].

Identifiers in Oxygene are case-insensitive.


Oxygene has global keywords and conditional keywords, that only act as keywords in a special context.

Oxygene Global Keywords
and as assembly begin break
case class const constructor continue
delegate div do downto else
end ensure event except exit
false finalizer finally for forward1
function1 future if implementation in
inherited interface invariants is locking
loop method mod module namespace
new nil not nullable of
old on operator or out
parallel private procedure1 property protected
public raise record repeat require
result self set shl shr
then to true try type
unit until uses using var
where while with xor yield
1These keywords are there for legacy only.
Oxygene Conditional Keywords
abstract add array of async default
each empty enum external final
finalizer flags global has implements
implies index inline iterator locked
matching nested notify override params
partial pinned read readonly reintroduce
remove sealed sequence of static step
unsafe virtual where write
The following words are only keywords in query expressions:
asc desc distinct equals from
group by into join on order by
reverse select skip take

Program Structure

Oxygene does not use "Units" like Delphi does, but uses .NET-namespaces to organize and group types. A namespace can span multiple files (and assemblies), but one file can only contain types of one namespace. This namespace is defined at the very top of the file:

namespace ConsoleApplication1;

Oxygene files are separated into an interface and an implementation section, which is the structure known from Delphi. The interface section follows the declaration of the namespace. It contains the uses-clause, which in Oxygene imports types from other namespaces:


Imported namespaces have to be in the project itself or in referenced assemblies. Unlike in C#, in Oxygene you cannot define alias names for namespaces, only for single type names (see below).

Following the uses-clause a file contains type declarations, like they are known from Delphi:

  ConsoleApp = class
    class method Main;

As in C#, the Main-method is the entry point for every program. It can have a parameter args : Array of String for passing command line arguments to the program.

More types can be declared without repeating the type-keyword.

The implementation of the declared methods is places in the implementation section:

class method ConsoleApp.Main;
  // add your own code here
  Console.WriteLine('Hello World.');

Files are always ended with end.


Variables in Oxygene can be declared in the head of a method or inside its body:

method MyClass.Foo;
  var1 : Integer; //Variable declared in header
  var1 := 5; //Assignment to variable
  var var2 : Integer; //Variable declared in the body
  var var3 : Integer := 10; //Variable declared and initialized in the body
  var var4 := 'foobar'; //String-Variable declared using type inference

As seen in the above example, in the method one can use type inference to delcare and initialize a variable without explicetly defining its type.


Constants can be defined as class members in the interface section or in the header of every method. Their value is defined via "=", not ":=", because it's a deinfition not an assignment. Type inference works with constants, too.

const pi = 3.1415926;

Their value can only be defined during declaration and will be evaluated at compile time.


Boolean and Binary Operators

As other Pascal languages, Oxygene does not distinguish between a boolean and and a binary and. The following operators are both boolean and binary: not, and, or, xor.

Additionally, there's the only-boolean implies-Operator. It combines two boolean values. The second expression is only evaluated if the first/left expression is true. If the first expression is false, the entire expression will be considered true.

  HasDriversLicense implies Age >= 16;

In combination with is and in the not operator can be used in a more human readable way:

if i not in [1,2,3] then
if i is not String then

Comparison Operators

Oxygene does have the following comparison operators: >=, <=, <>, =, >, <.

In Oxygene you can use the "Boolean Double Comparison":

if -2 <= a <= 2 then

is equal to

if (-2 <= a) and (a <= 2) then

Assignment Operators

To assign values in Oxygene, you normally use the := operator. For adding and removing event handlers (and only for that), Oxygene does know the "addition assignment operator" += and the "subtraction assignment operator" -=.

Arithmetic Operators

The operators for addition, subtraction, division and multiplication are +, -, /, *. Although the division-operator used with two integers creates in Oxygene already an integer division, it has still the "old" div operator (integer division) known from other Pascal languages. The modulo of two integers is calculated using the mod operator.

Member Access Operators

Oxygene offers two operators for accessing the members of an object. The period operator ".<code>" works as expected and will raise an exception when used on a nil-value.

Different from the period operator, which requires the value on its left to be assigned (and will usually throw a NullReferenceException if it is not), the colon operator allows to call members on any value, including nil. If the expression on the left of the colon is nil, the entire expression will automatically short-circuit to return nil as well.

var lGreatGrandDadsName := lUser:Parent:Parent:Parent:Name;

Bit Shifting Operators

<code>shl will shift bits to the left, shr will shift bits to the right.

Other Operators

  • @ is used to get the address of something, which for example is used when passing a method as parameter.*
  • [] is used to access array elements.
  • -> is used for lambda expressions.
  • as is a casting operator, throwing an exception if the cast is unsuccessful.
  • is checks if an object is assignable to a variable of specific type.
  • in checks if an element is in a collection of other elements, also used for Set-types.
  • ^ is the pointer dereferencing operator.
  • iif is the equivalent to the ternary operator in C-languages: var a := iif(b = 42, 3, 4); //3, if b = 42, 4 else

Operator Overloading

Operators can be overloaded in Oxygene using the class operator syntax:

class operator implicit(i : Integer) : MyClass;

Note, that for operator overloading each operator has a name, that has to be used in the operator overloading syntax, because for example "+" would not be a valid method name in Oxygene[3].

Control Structures

Blocks of Code

Blocks of code are created by surrounding them with begin and end. Variables declared in a code block are not visible / usable outside of it.

Conditional Structures

if Statement

A complete if statement in Oxygene consists of the

if {condition} then

The code can be a single command or a block of code. When nesting if statements without creating separate code blocks, else branches always belong to the next inner if branch, which is indicated by indentation in the following code:

 if {condition} then
   if {condition} then
case Statement

The case statement executes code, depending on the value of a variable:

case i of
  1,2,3: {code}
  4..9: {code}
  10: begin

Unlike Delphi, Oxygene also accepts types that are not enumerable such as strings.

The case statement can also be used to execute code depending on the type of a variable:

case foo type of
  Integer: Console.WriteLine(foo.ToString);
  Double: Console.WriteLine(foo.ToString('0.00'));
  Boolean: Console.WriteLine(iif(Boolean(foo), 'yes', 'no'));
  Console.WriteLine('Hu? What''s that?');


for Loop

In Oxygene, you can (but don't need to) declare the iteration variable inside of the loop's head and its scope will be limited to the loop's body:

for i : Integer := 0 to 42 do

This even compiles, if there's already a variable with the same name declared. This "outside variable" then can not be accessed from within the loop's body.

for loops can run backward (using downto instead of to) and make steps larger than one (0 to 42 step 4).

repeat-until Loop

The repeat-until loop is a post-test loop, which means its body is executed at least one time before the loop-condition is checked:

var i := 0;
until i = 10;
while-do Loop

The while-do is a pre-test loop, the condition is checked before the body is (perhaps) executed the first time.

var i := 0;
while i < 10 do
loop Loop

The loop loop executes its body without any condition indefinitely, until it is aborted using break (see below).

loop Console.WriteLine('foo'); //will run forever!
var i := 0;
loop begin
  if i = 10 then
for each (matching) Loop

With the for each loop one can iterate over a sequence, i.e. anything that implements IEnumerable and/or IEnumerable<T>. The "each" can be omitted.

for i in Enumerable.Range(1,10) do

As can be seen in the above example, the type of the iterator variable is inferred for typed sequences (i.e. a sequence implementing IEnumerable<T>).

Only items of a specific type can be filtered with the matching syntax:

for matching item : IComparable in items do

This will execute the loop body only for items implementing IComparable and "jumping over" other items in the sequence.

The (zero-based) index of the current iteration can be obtained with the index syntax:

for item in items index i do
  Console.WriteLine((i+1).ToString+'. Item: '+item.ToString);
Controlling Loops

Loops can be controlled by using the break or continue keyword. The former aborts the loop completely, the latter aborts the current iteration and starts the next one. Both keywords only affect the most inner loop.

Exception Handling

Oxygene has the try-except and try-finally statements for handling exception, which can be combined and used together.

  //Do something very, very dangerous
  //React if it goes wrong

The finally block will be executed regardless of an exception is thrown or not, and if only the finally block and no except block is there, the exception will "bubble up" in your program, while in an except block you have to use the raise; command to keep re-raise an already handled exception.

You can select on which types of exceptions you want to react:

 //Do something even more dangerous
  on e : BioHazardException do
    Console.WriteLine('omg, we released a dangerous liquid with the name: '+e.message);
  on NuclearException do
    Console.WriteLine('Ooops, we set of a nuke!');
  on Exception do
    Console.WriteLine('Something else went wrong, no idea what');

The last selector is used to catch every exception that wasn't handled before and can be seen as some kind of else-branch. You can also see, that the exception object e can be used or not.

You can filter exceptions further using the where-syntax:

 //You know what goes here ..
  on e : CategorizedException where e.CategoryId = 42 do
    Console.WriteLine('Got excpetion with of category 42');


As a .NET language, Oxygene uses the .NET type system: There're value types (like structs) and reference types (like arrays or classes).

Although it does not introduce own "pre-defined" types, Oxygene offers more "pascalish" generic names for some of them[4], so that for example the System.Int32 can be used as Integer and Boolean (System.Boolean), Char (System.Char), Real (System.Double) join the family of pascal-typenames, too. The struct character of these types, which is part of .NET, is fully preserved.

Type Visibility

As in all .NET languages types in Oxygene have a visibility. In Oxygene the default visibility is assembly, which is equivalent to the internal visibility in C#. The other possible type visibility is public.

  MyClass = public class

The visibility can be set for every type you define (classes, interfaces, records, ...).

Type Aliases

You can define an alias name for types, which can be used locally or in other Oxygene-assemblies, too.

  IntList = public List<Integer>; //visible in other Oxygene-assemblies
  SecretEnuerable = IEnumerable<String>; //not visible in other assemblies

Public type aliases won't be visible for other languages.

Value Types


Records are what .NET-structs are called in Oxygene. They are declared just like classes, but with the record keyword:

  MyRecord = record
    method Foo;

As they're just .NET-structs, records can have fields, methods and properties, but do not have inheritance and cannot implement interfaces.


Enumerations can be defined using the enum keyword or a shorter syntax:

  MyEnum1 = public enum(One, Two, Thee);
  MyEnum2 = public(One, Two, Three);

By default, the integer value representing one item in the enum is increased by 1 for every item. Declaring a enum using the flags keyword will assign every item a value of 2i, where i is the index of the item. You can define the value of an item manually, too.

MyFlags = flags(One, Two, Thee);
MyEnum3 = enum(One = 1, Two = 2, Three = 3);

Sets are convenient way of working with a small, defined number of ordinal values, like the elements of an enumeration. Every value is exactly zero ore one time in a set.

  MySet = set of MyEnum;

You can add values to a set or check, if a value is in a set:

var s : MySet := [MySet.One];
s := s + [MySet.Two];
if MySet.Three in s then

Other operations are subtraction, intersection (*) and checks for equality, inequality, subset and superset.

Internally sets are implemented using structs and these structs are usable from other languages like C#, too.

Nullable Types

Nullable types are a way, to store wether the value of a value type is set or not. The .NET framework provides the generic Nullable<T> struct for this purpose, which is integrated into the language in Oxygene.

When declaring e.g. a nullable Integer

var nullableInt : nullable Integer;

you can just assign a "normal" integer to it:

nullableInt  := 5;

You can use any method of the value's type on the nullable type:

if nullableInt.CompareTo(3) > 0 then
  Console.WriteLine('Is bigger');

You should consider the use of the colon-operator in this case, because it's "nil-safe" and won't throw an exception if the value is not set.

Nullable types in Oxygene can be uses inside expressions[5], where using a "normal" and a nullable type in one expression will in almost every case result in a nullable type.

var k := nullableInt  + 5; //k is nullable

Nullables can be used inside boolean expressions, where the equality comparisons (= and <>) will always result in non-nullable boolean, all other comparisons will create a nullable boolean:

if nullableInt = 5 then

To obtain the value of a nullable value, Oxygene provides the system method valueOrDefault:

var aInt := valueOrDefault(nullableInt, -1);

This will assign the value of nullableInt, if the value was set, and -1 otherwise. The last parameter can be omitted, then the default value of the non-nullable type will be used as "fallback"-value.

if valueOrDefault(nullableInt > 5) then
  Console.WriteLine("Is bigger!")

Here nullableInt > 5 creates a nullable boolean and valueOrDefault will return false, if the value is not set and its value otherwise.

Although there name indicates something else, nullable types are value types (so assigning one to another will create a copy). One can assign them the null / nil value, but only because there is an implicit conversion for this case. For the same reason, you can compare them to nil in order to find out, if their value was set:

if nullableInt = nil then
  Console.WriteLine('Value not set!');

Reference Types

When the type of a variable is reference type, then the variable only holds a reference to an instance of that type. Assigning the variable to another variable just copies the reference, so both variables reference the same instance. When there're no more reference to an instance, it will eventually get removed by the garbage collection (GC).

The null-reference (i.e. the value of a variable not referencing anything) in Oxygene is nil.


Oxygene uses a mixed Pascal / C style for declaring and initializing arrays. The type of an array is declared in the pascal-way

var a : Array of Integer;

but the instance is created using C-style (which is used always for creating instances in Oxygene)

a := new Integer[42];

Due to type inference you could of course omit the declaration.

In addition to these unbound array, Oxygene offers the possibility to use bound arrays. Bound arrays can have both the lower and upper bound defined (then they're of fixed size) or only the lower bound (then they're of variable size).

  ArrType1 = array[0..3] of Integer;
  ArrType2 = array[1..] of Char;
  ArrType3 = array[-2..2] of String;
var a := new ArrType2(10);

For fixed size arrays you don't need to create the instance. As you can see, the lower bound is allowed to be negative.

You can use char and enums as array indexes, too:

  a : Array[MyEnum] of Integer;
  b : Array[Char] of Byte;

Multidimensional arrays can be declared (or type inferred) like this:

var a := new Integer[3,4];
var b : Array[0..,0..] of Integer;

Inline array constants can be used like this:

var x : array of Integer := [1,2,3];
var b : array[0..,0..] of Integer := [[3,3,3],[4,5,6]];

A class is a data type that can contain fields, properties, methods, indexers and events. Also nested types can be declared inside a class.

Classes can be sealed (cannot be inherited), abstract or static. Classes can be declared as partial, so that the class declaration can span multiple files (but not multiple assemblies).

Classes can inherit other classes and implement interfaces.

Example of a class delcaration in Oxygene:

  MyClass = public class(ParentClass, ISampleInterface) //inherits ParentClass, implement ISampleInterface
    fFoo : Integer; //field
    method GetList(index : Integer) : String;
    method SetList(index : Integer; value : String);
    method DoSomething; //method
    property Foo : Integer read fFoo; //read-only property
    property List[index : Integer] : String read GetList write SetList; default; //(default) indexer
  SubClass nested in MyClass = protected class //Class nested in MyClass
    event SomethingHappens : MyEvent;

Interfaces are very important concept in the .NET world, the framework itself makes heavy use of them. Interfaces are the specification of a small set of methods, properties and events a class has to implement when implementing the interface. For example contains the interface IEnumerable<T> specifies the GetEnumerator method which is used to iterate over sequences.

Interfaces are declared just like classes:

  MyInterface = public interface
    method MakeItSo : IEnumerable;
    property Bar : String read write;

Please notice, that for properties the getter and setter are not explicetly specified.


Delegates define sigantures for methods, so that these methods can be passed in parameters (e.g. callbacks) or stored in variables, etc. They're the type-safe NET-equivalent to function pointers. They're also used in events.

To define a delegete one uses the method or delegate keyword. function and procedure work, too, but are deprecated.

  SomeCallback = public method(aParam : Integer) : Boolean;
  SomeEventHandler = public delegate(sender : Object; e : SomeEventArgs);

Delegates can be invoked by using there Invoke or BeginInvoke method, or by just calling them like methods:

var a : SomeCallback := @anAppropriateMethod;

As you can see, when assigning a method to a delegate, one has to use the @ operator, so the compiler knows, that one doesn't want to call the method but just assign it.

Oxygene can create anonymous delegates, so for example you can pass methods to the Invoke method of a control without declaring the delegate:

method MainForm.MainForm_Load(sender: System.Object; e: System.EventArgs);

An anonymous delegate with the siganture of the method DoSomething will be created by the compiler.

This can be combined with anonymous methods:

method MainForm.MainForm_Load(sender: System.Object; e: System.EventArgs);
  Invoke(method; begin

Oxygene supports polymorphic delegates, which means, that delegates which have parameters of descending types are assignment compatible. Assume two classes MyClass and MyClassEx = class(MyClass), then in the following code BlubbEx is assignment compatible to Blubb.

  delegate Blubb(sender : Object; m : MyClass);
  delegate BlubbEx(sender : Object; mx : MyClassEx);

Object Oriented Programming

Oxygene is an object-oriented language, which means it uses classes, which can hold data and execute code, to design programs. Classes are "prototypes" for objects, like the idea of an apple is the prototype for the apple you can actually buy in the shop. You know, that an apple has a color and you know, that it can be peeled: that are is data and executable "code" for the apple class.


Methods are declared in the interface section and implemented in the implementation section of a file:

  MyClass = public class
    method DoSomething(aParam : Integer);
method MyClass.DoSomething(aParam : Integer);

When using class method instead of method, the method will be static, meaning it's called on the class itself and not on one instance of that class. One can only access other class members, not instance members from this method.

Method Parameters
Parameters are declared both in the interface and implementation section. If more than one parameter in a row has the same type, they can be defined with specifying the type only once:
param1, param2 : Integer

Parameters can be provided with a default value, which is used when the parameter isn't passed to the method when calling it:

method Foo(HasToBePassed : String; Bar : Integer := 42);

The default value is only defined in the interface section!

When declaring an array-parameter with the params keyword, the array can be passed as sequence of parameters when calling the method:

method MethodWithManyParameters(params manyParameters : Array of Integer);
// ...

Modifiers are keywords placed behind the method declaration. They change the behaviour of the method they're applied to. The modifier is not repeated in the implementation section.

There're the following modifiers for methods:

Oxygene Modifiers for Methods
empty The empty modifier tells the compiler, that actually no implementation for this method exists. Therefore no method stub in the implementation section is needed.
method DoNothing; empty;
virtual Virtual methods can be overridden in descendant classes.
abstract The abstract modifier creates an abstract method, which is a method that must be implemented in a derived class. Abstract classes are automatically virtual.
override In a derived class a method with the override modifier overrides a virtual method of the base class.
reintroduce Using the reintroduce modifier will tell the compiler, that you really want to re-implement a base classes virtual method.
final When a virtual method is marked as final in a descendant class, descendants of that class can no longer override the method.
locked Thread-safe methods can be created using the locked modifier. By default, locking works an the entire instance (i.e. self), but one can specify the field to lock on: method LockedMethod; locked on fAField;;
async Additionally one can create asynchronous methods with the async modifier. This means, a call to a method marked with this modifier will immediately return and the code of the method will be executed in a separate thread. The following will output "First" and after half a second the numbers 0 .. 10:
  MyClass = public class
    method DoSomething; async;
class method ConsoleApp.Main;
  var mc := new MyClass;
method MyClass.DoSomething;
  for i : Integer := 0 to 10 do
external Methods from unmanaged libraries (e.g. the Windows-API) can used when a method is declared with the external modifier and the DllImportAttribute[6].
unsafe Methods marked as unsafe make it possible to use unmanaged code, which for example makes use of pointers.
implements With implements one can specify which method of an interface a method implements:
method CompTo(other: MyClass): System.Int32; public implements IComparable<MyClass>.CompareTo;
The public visibility modifier can be omitted, then the implementation is private (the class has to be explicetly cast into the interface to access the method).
iterator An iterator (in .NET represented by the IEnumerator interface) is an object, which has a method that will return a new element of a sequence every time this method is called. This can be used in a for-each-loop. When giving a method the iterator modifier, the compiler will create such an iterator object from the method. Inside the method you have to use yield to tell the compiler which elements the sequence should consist of:
  MyClass = public class
    method GetEvenNumbers: sequence of Int32; iterator;
// ...
method MyClass.GetEvenNumbers: sequence of Int32;
  for i: Int32 := 0 to 100 step 2 do
    yield i;
partial Partial methods can be declared as empty methods in one part of a partial class (i.e. they have the modifiers partial; empty;) and implemented in another part of the partial class. If they are not implemented in another part, all calls to the method will be removed at compile time.
Extension Methods

Extension methods are class methods that are treated in a special way by the editor (especially IntelliSense) and the compiler. They're defined and implemented in one class, but are called on another class (at least it looks like if they were).

For example, if you want to define a method Implode, which creates a string representation of a sequence, you can create a class and such a method in it:

  MyClass = public class
    class method Implode<T> (aSequence : IEnumerable<T>) : String;

You'd call this method like this: MyClass.Implode(someSequence)

With extension methods, you can do it much more elegant. Class and method are decorated with the appropriate attribute to turn the method into an extension method:

  [System.Runtime.CompilerServices.Extension] //namespace can be omitted
  MyClass = public class
    class method Implode<T> (aSequence : IEnumerable<T>) : String;

No you can call the method directly on any sequence: someSequence.Implode
IntelliSense will show the method on any sequence, too.

At compile time, the method call will be re-written to the "normal" call to MyClass.Implode.

The Extension attribute is defined in the System.Core.dll starting with version 3.5 of the .NET framework. If you don't want to use that version of the framework, you can define the attribute for yourself (in the appropriate namespace) or use Mono's System.Core.dll.

Extension methods are a very important part of the implementation of LINQ.


Fields store data and can be instance or class members. They should only be used internally, to make a value public, use properties.

MyClass = public class
  fInstanceField : String;
  class var fClassField : Integer;

Fields can be marked as read-only (see sample code below), which means that their value can only be assigned in the (class) constructor. In contrast to constants a field's value will be evaluated at runtime and therefore can be calculated using complex expression.

Initial values of a field can be defined together with the declaration:

fStartTimeAsString : String := DateTime.Now.ToString; readonly;

The compiler will put these initializations into the constructor, normally before calling the inhertied constructor[7].

Delegating Interface Implementation

Fields can be used to delegate the implemenation of an interface, if the type they're of implements this interface:

Implementor = public class(IMyInterface)
  // ... implement interface ...
MyClass = public class(IMyInterface)
  fSomeImplementor : Implementor; public implements IMyInterface; //takes care of implementing the interface

In this example the compiler will create public methods and properties in MyClass, which call the methods / properties of fSomeImplementor, to implement the members of IMyInterface. This can be used to provide mixin-like functionality[8].


Properties are an abstraction of values describing the object. They often provide controlled access to the value of a field. Properties have a setter and a getter, which are methods called when someone sets / gets the value of the property.

  MyClass = public class
    fStringField : String;
    method GetIntField : Integer;
    method SetIntField(value : Integer);
    property LonelyProperty : Boolean;
    property StringProperty : String read fStringField write fStringField;
    property IntProperty : Integer read GetIntField write SetIntField;

In the above example three properties are defined. For the first one, the compiler will generate a field implictely and delegate the property's access to this field. For the second property, methods that read and write the value of property from / to the specified field are generated. The field for read and write and access do not have to be the same. Regarding the third property, read and write access are delegated the appropriate methods.

Using Inline Expression one can save one or another method:

  Circle = public class
    property Radius : Double := 1.0;
    property Area : Double read Math.Pi * Radius * Radius;  //inline expression

The example also shows, that the value of properties with implicit fields can be initialized in the interface section.

There can be different visibility levels for read and write access, e.g. using protected write instead of just write.

Properties can be made virtual or abstract by applying the appropriate modifier (virtual or abstract).

Property Notification

Property notification is used mainly for data binding, when the GUI has to know when the value of a property changes. The .NET framework provides the interfaces INotifyPropertyChanged and INotifyPropertyChanging (in .NET 3.5) for this purpose. These interfaces define events which have to be fired when a property is changed / was changed.

Oxygene provides the notify modifier, which can be used on properties. If this modifier is used, the compiler will add the interfaces to the class, implement them and create code to raise the events when the property changes / was changed.

property Foo : String read fFoo write SetFoo; notify;
property Bar : String; notfiy 'Blubb'; //will notify that property "Blubb" was changed instead of "Bar"

As you can see, the modifier can be used on properties which have a setter method. The code to raise the events will then be added to this method during compile time.


Indexers are properties that can be accessed as if they were arrays. In Oxygene a class can have an arbitrary number of indexer properties, but only one index property can be the default indexer (which is defined by applying the default modifier).

  MyClass = public class
    method GetCell(x, y : Integer): Integer;
    method SetCell(x, y : Integer; value: Integer);
    method GetColumn(x : Integer) : Array of Integer;
    property Cell[x, y : Integer] : Integer read GetCell write SetCell; default;
    property Column[x : Integer] : Array of Integer read GetColumn;
// ...
var aMyClass := new MyClass();
aMyClass[0,0] := 5;
var aCol := aMyClass.Column[3];

Indexers cannot have implicit getters or setters, these have to be methods or inline expression.

Indexers with the same name can be overloaded by their parameter type and parameter count.


An event is a member of a class or record that others can add delegates as event handlers to, which will be called, when the event is fired. Delegates can also be removed from the event.

In Oxygene one can define an add and a remove method or just which delegate field should be used for holding the event handlers.

Additionally the compiler can generate a "raise method", so that events can be raised from external classes.

  MyClass = public class
    fMember : SomeEventHandler; //field for holding event handlers
    method MethodForAdding(param : SomeEventHandler);
    method MethodForRemoving(param : SomeEventHandler);
    event SimplestEvent : SomeEventHandler; //simplest declaration, compiler does the rest
    event SomeEvent : SomeEventHandler delegate fMember; //event handlers will be stored in fMember
    event SomeOtherEvent : SomeEventHandler add MethodForAdding remove MethodForRemoving; //methods will be used for adding and
                                                                                          //removing event handlers
    event YetAnotherEvent : SomeEventHandler raise; //method for external raising of the event will be added

add, remove and raise can be decorated with a visibility modifier (e.g. protected raise) to limit their visibility.

Event handlers are added and removed using the += operator and -= operator respectively.

Language Features

New Language Features in Version 3.0

Parallel Programming

Oxygene 3.0 introduces a wide range of language concepts that push the envelope for parallel programming and enable developers to create applications that seamlessly scale up for multi-core and many-core systems. This includes support for Futures, Parallel Loops, Asynchronous Statements, an improved locked directive, and more.

Property Notifications

Native language support for property notifications makes it easy to develop solutions that follow the Model/View/Controller design pattern or generally react in well-defined ways to property changes.

Nullable Expressions

Oxygene's Expression syntax has been expanded to provide full support for nullable types in arithmetic and other expressions, making the language integration of nullables even more seamless than in 'Joyride'. Improvements have also been made for casting between compatible nullable types, such as assigning a nullbale Int32 to a nullable Int64, etc.

New Language Features in Version 2.0 ('Joyride')

Sequences and Query Expressions

Query Expressions, also known as "Language Integrated Query", or LINQ for short, are a powerful new language feature that allows you to combine the querying capabilities of database languages such as SQL and apply it to any type of data, natively within the Oxygene language.

Queries can be written to work on any type of structured collection, from simple lists and arrays to database tables and other data structures. Combined with the DLinq and XLinq libraries provided by Microsoft as part of the .NET 3.5 runtime, the feature can be used to efficiently query data from database sources and XML documents, without actually retrieving the entire set of data into memory.

var u := from u in lUsers
           where u.Age = 35
           order by u.Name;

Lambda Expressions

Mostly used alongside LINQ and query support, lambda expressions provide a unique syntax for passing dynamic expressions as part of method parameters.

var lFiltered := lUsers.Where(u -> u.Age = 35);

Anonymous Types

Once again mostly used in LINQ expressions, anonymous types allow you quickly declare unnamed classes within a method body, to group related values in a common entity.

var lUser := new class(Name := 'Peter'; Age := 49);
Console.WriteLine(lUser.Name+' is '+lUser.Age+' years old');

Partial Methods

New Partial Method support allows you to define a stub for a method in one part of a class, allowing an optional implementation to be provided by another partial. If no implementation is provided, the method and any calls to it will be omitted from the generated assembly.

Partial Methods make it easy for auto-generated code to define methods that can be implemented by the user. This is used extensively in our new Cocoa# support, as well as upcoming support for LINQ to SQL.

Enhanced Nullable Types

'Joyride' enhanced support for nullable types, making them a full language feature that fits in neatly with the other types rather than having nullable types feel like a runtime trick. For example, variables defined as nullable Int32 allow full access to members of Int32 and behave like a true Int32 in every sense - with the addition of allowing nil values.

In combination with the new ":" operator (described below) and the newly introduced ValueOrDefault() helper function, nullable types are now easier to use than ever, and feel more natural than in any other .NET language.

Extension Methods

Extension methods are a feature introduced by Microsoft in the .NET 3.5 runtime to support LINQ, but can be used in Oxygene in a wide variety of scenarios and on all framework versions.

Simply put, Extension Methods are methods declared in a static class that extend an existing class or interface, and can be invoked on a variable of that type. For example the Where extension method provided by .NET 3.5 extends IEnumerable<T>, and thus can be used on any sequence of objects to filter the collection on an arbitrary condition, even though IEnumerable<T> does not provide a Where member:

var lUsers := array of User;
var lPauls := lUsers.Where(u -> u.Name = 'Paul');

Anonymous Methods

Anonymous methods make it possible to specify code assigned to event handlers or passed to delegates right within the body of another method. They not only allow you to skip manually declaring a method within the class, but they also seamlessly allow access to any local variables available within the context where the anonymous method is written.

method SetEventHandler;
  var lNewCaption := 'Clicked!';
  Button1.Click += method(Sender: Object; ea: EventArgs); begin
      Button1.Text := lNewCaption
      MessageBox.Show('the button was clicked.');

Colon ':' Operator

'Joyride' introduces a new operator that can be used anyplace the familiar "." can is used, be it to access a method, properties or other members of a type. Different from the "." operator, which requires the value on its left to be assigned (and will usually throw a NullReferenceException if it is not), the new ":" operator will allow to call members on any value, including nil. If the expression on the left of the colon is nil, the entire expression will automatically short-circuit to return nil as well.

This makes it very easy to access nested members in object hierarchies, when multiple if assigned() checks would otherwise be needed. (BLOG)

var lGreatGrandDadsName := lUser:Parent:Parent:Parent:Name;

'Params' Keyword

The params keyword makes it easy to define methods that take a variable number of arguments. By closing the list of parameters with an array parameter prefixed with the params keyword, you can enable callers of your method to pass variable numbers of elements to method calls, which will automatically be converted into an array. This makes it easier to call the method, especially from languages like C#, where constructing an inline array is long and unwieldy.

method Format(aFormat: string: params values: array of Int32);
Format('...', 1, 2, 3, 5, 27);

'implies' Operator

The new implies operator was designed specifically for require/ensure clauses and class invariants, but can also be used elsewhere in code. Similar to and or, it combines two boolean expressions; the difference is that with implies, the second expression is only evaluated if the first/left expression is true. if the first expression is false, the entire expression will be considered true.

  HasDriversLicense implies Age >= 16;

Type Inference for 'for each' Loops on Generic Sequences

For 'Joyride', for each loops have been improved to automatically infer the type of the loop variable when working on a generic IEnumerable<T> or other strongly-typed sequence, avoiding the need to manually specify the type name. As a side effect, for each loops will now always implicitly define their loop variable.

var lUsers: array of Users;
for each u in Users do
  Console.WriteLine(u.Name); // Compiler knows "u" is a "User"

For non-generic enumerations (IEnumerable), a explicit type declaration will be required inside the for each loop; the compiler will not automatically infer to use System.Object.

'index' Operator for 'for each' Loops

The Syntax for each loops has been expanded in 'Joyride' to allow for an optional index variable to be defined, which will count from 0 through the number of elements looped. This is helpful in scenarios where the number of elements processed is needed as part of the loop, be it to access a separate collection by index, or to use different code to handle the first or even/odd elements.

When using for each matching or other mechanisms (such as LINQ) to filter down the collection, the index will only count those elements that actually execute the loop.

for each u in Users index i do begin
  if i > 0 then Console.Write(';');

New Language Features in Version 1.5 ('Floorshow')

Generic Methods

Use Generics to implement strongly typed methods with and parameterized types (.NET 2.0 only).


Easily implement collections and enumerable classes using iterators for both .NET 1.1 and 2.0 using the new 'iterator' directive and the 'yield' keyword.

method CountTo100: Int32; iterator;
  for i: Int32 := 0 to 100 do yield i;

Nullable Types

Avoid boxing by using new nullable value types on the .NET 2.0 framework. Support for nullable types has been vastly enhanced for 'Joyride' (see above).

var i := nullable Int32;
if assigned(i) then i.CompareTo(5);

Nested Types

Define and implement nested types using Oxygene's new and intuitive 'nested in' syntax

  HelperClass nested in MainClass = class //...

Dual-visibility for Properties

Define properties with different visibility levels for getter and setter, for example allowing public reading and protected writing of properties:

property Count: Int32 read fCount protected write SetCount;

Extended Constructor Calls

Create objects and initialize properties in a single statement

var b := new Button(Width := 150; Height := 25);

Fixed Size Buffers

Use Fixed Size Buffers to declare efficient inline arrays inside your records, in "unsafe" code.

New Language Features over Object Pascal in Version 1.0

Generic Types

Use Generics to implement strongly typed containers and parameterized types.

Class Contracts

Oxygene is the first mainstream .NET language to provide native support for Design By Contract like constructs, with pre-conditions, post-conditions and invariants.

Namespace Support

Namespaces are one of the great basic concepts of the .NET framework that most developers take for granted. Oxygene provides three basic features that allow developers to work with namespaces.

Virtual Properties

Virtual Properties and Events allow you to more easily define abstract classes and interfaces, or overwrite existing framework interfaces that contain properties.

Enhanced Events Support

Oxygene introduces a new syntax for defining and working with events to the Object Pascal language.

Asynchronous Methods and Thread Synchronization

Easily write multi-threaded applications using Oxygenes' async keyword and asynchronous methods. Use the locked and locking keywords to write thread-safe applications.

Partial Classes

The only .NET compiler to provide partial classes support for .NET 1.1.

Operator Overloading

Make your classes intuitive to use by providing custom operator overloads for common operations such as addition or subtraction.

Class References & Virtual Constructors

Easily implement the Factory Pattern or dynamically create object instances using Oxygene's Class References (Meta Classes).

Enhanced Loops

Oxygene enhances the classic for/to loop to allow inline declaration of the loop variable type. It also provides a new for each loop type for looping across .NET IEnumerable and IEnumerable<T> types, as well as an infinite loop loop.

Inline Variable Declarations and Type Inference

Declare new variables using the 'var' statement inside your method bodies to keep them with the code that uses them. Avoid retyping type names and let Oxygene infer new variable types from the assigned value.

Inline Property Readers

Use inline code to implement simple property readers, such as

property Foo: String read 'Bar';

Enhanced 'case of' and 'case type of' statements

'case' statements can use strings or other non-ordinal types, as well as the new 'case type of' statement to execute different cases depending of an object's type.

case aClassID.ToUpper of
   'XYZ': result := TMyXYZClass;
   'ABC': result := TMyOtherClass;
  else raise new Exception('Invalid Class ID');
case aClass type of
   TMyXYZClass: TMyXYZClass(aClass).DoSomething;
   TMyOtherClass: TMyOtherClass(aClass).DoSomethingElse;
   else raise new Exception('Invalid Class Reference');

Enhanced 'try/finally/except'

Combine 'finally' and 'except' to create more concise and efficient exception handling code.

Exception Filters

Previously only available in Visual Basic .NET, Exception Filters provide extended flexibility for catching exceptions over common 'try/except' blocks.

Boolean Double Comparisons

Easily compare values against boundaries with statements such as

if 0 <= x < Count then //...

Empty Methods

Quickly define class interfaces to flesh out later or empty methods to be overridden in descendant classes.

Static Classes

Implement static classes that cannot be instantiated at runtime, but provide static functionality to your project.

Enhanced 'exit' statement

Use the improved exit statement to terminate methods and set a return value in a single step.

Enhanced 'is not' and 'not in' statements

Use the new 'is not' operator to write more readable type check statements, and 'not in' for improved set handling.

Differences between native Delphi and Oxygene / Delphi Prism

Deprecated Keywords

  • unit: Replaced with the namespace keyword. Since Oxygene doesn't compile per-file but per-project, it does not depend on the name of the file. Instead the unit or namespace keyword is used to denote the default namespace that all types are defined in for that file
  • procedure and function: These two keywords have been replaced with the method keyword.
  • overload: In Delphi Prism all methods are overloaded by default, so no special keyword is needed for this.
  • .Create(): This constructor call has been replaced by the new keyword. It can still be enabled in the project options for legacy reasons.


Some people would like to port their Win32 Delphi code to Prism as is. This is not possible because while Prism looks like Delphi there are enough changes to make it incompatible for a simple recompile. So while the name makes you think it is just another version of Delphi that is not completely true.[9]

On top of the language differences the Visual Component Library framework is not available in Delphi Prism.[10] This makes porting even more difficult because classic Delphi code relies heavily on the VCL.

Code examples

Hello World

namespace HelloWorld;
  HelloClass = class
    class method Main; 
class method HelloClass.Main;
  System.Console.WriteLine('Hello World!');

Generic container

namespace GenericContainer;
  TestApp = class
    class method Main;
  Person = class
    property FirstName: String;
    property LastName: String;      
class method TestApp.Main;
  var myList := new List<Person>; //type inference
  myList.Add(new Person(FirstName := 'John', LastName := 'Doe'));  
  myList.Add(new Person(FirstName := 'Jane', LastName := 'Doe'));
  myList.Add(new Person(FirstName := 'James', LastName := 'Doe'));  
  Console.WriteLine(myList[1].FirstName);  //No casting needed

Generic method

namespace GenericMethodTest;
GenericMethodTest = static class
  class method Main;
  class method Swap<T>(var left, right : T);
  class method DoSwap<T>(left, right : T);
class method GenericMethodTest.DoSwap<T>(left, right : T);
  var a := left;
  var b := right;
  Console.WriteLine('Type: {0}', typeof(T));
  Console.WriteLine('-> a = {0}, b = {1}', a , b);
  Swap<T>(var a, var b);
  Console.WriteLine('-> a = {0}, b = {1}', a , b);
class method GenericMethodTest.Main;
  var a := 23;// type inference
  var b := 15;
  DoSwap<Integer>(a, b); // no downcasting to Object in this method.
  var aa := 'abc';// type inference
  var bb := 'def';
  DoSwap<String>(aa, bb); // no downcasting to Object in this method.
  DoSwap(1.1, 1.2); // type inference for generic parameters
class method GenericMethodTest.Swap<T>(var left, right : T);
  var temp := left;
  left:= right;
  right := temp;

Program Output:

Type: System.Int32
-> a = 23, b = 15
-> a = 15, b = 23
Type: System.String
-> a = abc, b = def
-> a = def, b = abc
Type: System.Double
-> a = 1,1, b = 1,2
-> a = 1,2, b = 1,1


See also


  1. [1] Embarcadero Delphi Prism page, at the bottom can be seen that they license the Oxygene Compiler.
  2. http://prismwiki.codegear.com/en/Special_Identifier_Escape_Syntax
  3. http://prismwiki.codegear.com/en/Operator_Overloading
  4. http://prismwiki.codegear.com/en/Built-In_Types
  5. http://prismwiki.codegear.com/en/Nullable_Types_in_Expressions
  6. http://prismwiki.codegear.com/en/DllImportAttribute
  7. http://prismwiki.codegear.com/en/Fields#Field_Initialization
  8. http://prismwiki.codegear.com/en/Provide_Mixin-like_functionality
  9. [2] A Stack overflow discussion where people remark that Delphi Prism is not Delphi Win32.
  10. [3] Delphi Prism 2010 review where they state in the third paragraph that VCL.net is not available.

External links

Template:RemObjectsko:크롬 (프로그래밍 언어) ru:Oxygene (язык программирования)

Personal tools

Served in 1.124 secs.