Oxygene Language Features
While more details about Oxygene and it's language features can be found in the
documentation wiki
and on CodeGear's Delphi
Prism home page, the following will give a brief introduction to some of the
more exciting features provided by the Oxygene language:
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 nullable Int32 to a nullable
Int64, etc.
Improved QA Analysis Tools
Improvements have been made to Oxygene to provide better feedback on quality of
code, including new Code Flow Analysis and FxCop Code Analysis options integrated
with the compiler, and the option to enforce proper case when using identifiers.
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 in 2.0.3
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;
begin
var lNewCaption := 'Clicked!';
Button1.Click += method(Sender: Object; ea: EventArgs); begin
Button1.Text := lNewCaption
MessageBox.Show('the button was clicked.');
end;
end;
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 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.
ensure
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 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(';');
Console.Write(u.Name);
end;
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).
Iterators
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;
begin
for i: Int32 := 0 to 100 do yield i;
end;
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
type
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 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
Write 'case' statements using strings or other non-ordinal types, and use the new
'case type of' statement to execute different cases depending of an object's type.
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.