Oxygene (programming language)
This page was last modified on 1 June 2016, at 17:00.
|First appeared||7.1.73 / April 23, 2014|
|Stable release||8.2 / November 13, 2015|
|Object Pascal, C#|
Oxygene (formerly known as Chrome) is a programming language developed by RemObjects Software for Microsoft's Common Language Infrastructure and the Java Platform. Oxygene is Object Pascal-based, but also has influences from C#, Eiffel, Java, F# and other languages. Compared to the now deprecated Delphi.NET, Oxygene does not emphasize total backward compatibility, but is designed to be a "reinvention" of the language, be a good citizen on the managed development platforms, and leverage all the features and technologies provided by the .NET and Java runtimes. Oxygene offers full integration into Visual Studio 2010 and 2012 as a commercial product, and a freely available command line compiler. Starting 2008, RemObjects Software has licensed its compiler and IDE technology to Embarcadero to be used in their Embarcadero Prism product .
RemObjects software came from a Delphi background. In 2002, RemObjects sought to expand its developer libraries into the Microsoft .NET Framework, so naturally they considered Delphi for .NET for the job. According to the RemObjects Chief Architect, it seemed like “Borland had developed Delphi for .NET with one main goal in mind: to hide the transition from Win32 to .NET from the developers.” As a result, Delphi for .NET “introduced many Delphi-isms and Win32-isms that felt out of place and awkward in the .NET world.”
As a result, RemObjects chose to use C# for its .NET projects instead of Delphi. But its engineers really missed the Pascal syntax, so eventually RemObjects decided to invent a language for .NET with the Pascal syntax, and Oxygene was born. Its code name was Adrenochrome, which was later shortened to Chrome, and eventually renamed to Oxygene.
The Oxygene programming language originated from Delphi and Object Pascal, but was designed to reflect the .NET programming paradigm and produce CLR-compliant assemblies. Thus, Oxygene does not support all the language features from Object Pascal and Delphi, but it does leverage all the features and technologies provided by the .NET runtime.
New language features in Oxygene 3.0 include support for parallel programming, property notifications for the Model/View/Controller design pattern, nullable expressions, and improved QA analysis tools.
Oxygene is a fully object oriented language that lets developers write code that runs on the .NET/Mono, Java/Android or Objective-C Runtime Environments, respectively. It is based around and builds on the language structures of Pascal and Object Pascal.
Oxygene generates code that uses Garbage Collection (GC) on the .NET and Java runtimes and Automatic Reference Counting (ARC) on the Objective-C runtime. This means that regardless of platform, the management of object life times is taken care of without explicit code needed from the developer, although the exact underlying semantics may differ slightly.
- 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:
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 alias names cannot be defined for namespaces, only for single type names (see below).
Following the uses-clause a file contains type declarations, like they are known from Delphi:
interface type ConsoleApp = class public class method Main; end;
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 placed in the implementation section:
implementation class method ConsoleApp.Main; begin // add your own code here Console.WriteLine('Hello World.'); end; end.
Files are always ended with end.
As an object oriented language, most code written in Oxygene lives in "Classes". Classes are an amalgamation of data and related functionality, and can consist of fields, methods, properties and — on .NET — multicast events.
Oxygene classes support all features familiar from other modern development languages: inheritance allows classes to descend from one another, extend each other, and be used polymorphically. This is extended by support for interfaces, which allow unrelated classes to implement common well-defined sets of APIs to be used in a consistent manner. Of course, classes can be abstract (i.e. need to be inherited from to become useful) and sealed (i.e. prohibited from being extended further).
type MyBetterButton = class(Button) … end;
Class members, such as methods, properties and events, can have different visibility scopes, controlling how they can be accessed from within the class or externally from other classes. Properties can have different visibility scopes for read and write access, respectively. Members can be marked virtual so they can be overridden in descendant classes — one of the cornerstones of polymorphism.
In addition to members, classes can also define invariants that will help with proving the consistency of the class during runtime. Invariants are boolean statements that describe the valid state of each object, and if present, the compiler will automatically ensure that invariants will be validated whenever necessary, detecting invalid object state and programing errors that cause it early on. Invariants are one half of Oxygene's implementation of Class Contracts.
Individual instances of classes are referred to as "Objects".
The bulk of code in a project exists within the bodies of a class's methods. A method body is surrounded with the "begin" and "end" keywords, and can contain a list of statements, separated by semicolons, that will be executed in sequence when the method is called.
In addition to simple statements, such as calls to other methods, assignments or arithmetic expressions, Oxygene of course provides a wide range of code flow statements to express application logic, such as for/to, for/each, while, repeat/until and infinite loops, "if" and "case" statements, assignments and of course method calls.
Expressions are a certain subset of statements that are considered to have a value that can be reused or built upon. For example, in the following to statements:
var x := 5 + 9; (5 + 9).ToString;
the "5 + 9" statement is an expression that applies the "+" operator to the values "5" and "9". The result of that expression can be used further, for example to be assigned to the variable "x", or to have the "ToString" method called upon.
Not all statements are expressions, so the following code is not valid:
var y := Console.WriteLine("Hello");
because the call to "Console.WriteLine" is a statement without (return) value.
The type system in Oxygene is rooted, that means every type ultimately descends from the common base class, "Object"(1). Oxygene automatically boxes and unboxes so called simple types — such as Integers — as necessary, making the distinction between objects and simple types irrelevant to the Oxygene developer for most cases. Oxygene also supports the concept of "nullable" simple types. Nullable types are fully supported in expressions.
- Other Types
Oxygene also supports a range of intrinsic types that are not classes in the strictest sense — although instances of them can be treated as objects. These include "Enums" to define a group of distinct related values, "Arrays" that contain a numbered list of elements accessible by index, and "Sequences" which similarly contain a list of elements that can be accessed sequentially but not by index.
Oxygene is a strongly-typed language by design, meaning that type safety is enforced and method calls are validated as compile-time. At the same time, it provides powerful features that let code break out of the confines of the safe type system, if needed. These include duck typing and soft interfaces which allow compatible objects to be used polymorphically without having a common ancestor, and the dynamic type, which allows arbitrary (checked at runtime) method and property calls on objects whose type is not known at compile time.
Oxygene identifies types by a unique combination of their name, and an (optional) namespace prefix. By default, a type's namespace is defined by the global namespace name declared for the file that the type is defined in, but individual type declaration can override the namespace by providing what is referred to as a "fully qualified type name":
namespace Foo; // default "current" namespace for types in this file … type MyType = class … end; // "Foo.MyType" … Bar.MyOtherType = class … end; // "Bar.MyOtherType"
When referring to (i.e. using) types, their names can be specified using the full name, or the short name can be used if the type exists in the "current" namespace or a namespace referenced in the "uses" clause:
namespace Foo; … uses Bar; … var x: MyOtherType; // finds "Bar.MyOtherType"
Generics are a core feature of modern languages today, and Oxygene provides full support for them on both .NET and Java.Simply put, generics allow the developer to declare classes that make strongly-typed use of other types, without knowing the exact type at the time of implementation.
A common example is a List class, which can be used in different incarnations to hold different types — for example a list of Integers, a list of strings or a list of custom types called Foo.
Rather than implementing IntegerList, StringList and FooList separately (duplicating a lot of code) or falling back to a plain list of untyped "Objects" (which loses type safety and requires unnecessary casts when accessing elements) a generic List can be defined, where T is a placeholder for any given type.Throughout the implementation of List, the name "T" can be used to refer to "the type that this list works on", without ever having to become concrete. (But of course generics can impose limitations on their types, for example an OrderedList would specify that its members need to implement an interface that makes them sortable.)
Users of the class can instantiate concrete versions of a generic simply by specifying an actual type name, e.g.:
var x := new List<Int32>; var y := new List<String>;
and when working with these lists in "x" and "y", they can be accessed with the safe knowledge that all members of the list are Int32s or Strings, respectively.
- Sequences & Queries
Sequences are a special type in the language and can be thought of as a collection of elements, similar to an array.
In contrast to arrays, sequences do not imply a specific form of data storage, but can represent any collection of elements that is accessible in a specific order. This could be an array (and as a matter of fact, all arrays can be treated as a sequence) or a different data store, such as a linked list, a binary tree or a custom collection implementation.
Sequences can also represent non-static data that is retrieved or generated on the fly, as the sequence is enumerated. For example, one could implement a sequence that calculates all digits of Pi, or retrieves RSS headlines downloaded from a server.In Oxygene, sequences are represented by the "sequence of" keyword (analogous to the "array of" syntax), so a variable holding a sequence of strings would be defined as follows:
var Names: sequence of String;
A variable defined like this would then be capable of referring to any kind of sequence — be it an array, a standard generic List collection class or a custom sequence implementation.The main power of sequences arises when used in combination with Query Expressions, also known as LINQ.Query Expressions provide an SQL-like syntax to perform actions or apply filters to sequence types — for example to narrow down a sequence to all elements with a particular property value, or to sort a sequence using a property:
var byLength := from n in Names order by n.Length;
Oxygene 5.2 also extends the Oxygene language with support for native tuple types for both .NET and Java. Tuples are a new core type in the language, like arrays or sequences, and are designed to hold a set of specific typed objects.
Tuples make it easy to pass around groups of values (for example a String and an Integer), store them in arrays or collections, even return multiple values from function calls.
You can define a tuple variable such as:
var t: tuple of (String, Int32, Boolean);
and you can access individual members of the tuple using the strongly typed  indexer:
var s := t; var i := t;
where each index is strongly typed, i.e. the compiler knows that
t is an
Int32 type. You can also declare tuple literals using the new () syntax:
<syntaxhighligh tlang="oxygene"> t := ('Holla', 23, false); </syntaxhighlight>
and even assign tuples back to individual values:
var s: String; var i: Int32; (s, i) := MyTupleMethod();
Differences between native Delphi and Oxygene
- 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: method is the preferred keyword, though procedure and function still work.
- overload: In Oxygene 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
- string: Characters in strings are zero-based and read-only. Strings can have nil values, so testing against empty string is not always sufficient.
Some people would like to port their Win32 Delphi code to Oxygene as is. This is not possible because while Oxygene looks like Delphi there are enough changes to make it incompatible for a simple recompile. While the name appears to give it the appearance of another version of Delphi that is not completely true. The links is probably mostly kept alive (REMObjects is afaik still Delphi component ISV) for marketing purposes, just like e.g. Component Pascal names itself Pascal, not the Oberon that it really is inspired by.
On top of the language differences the Visual Component Library framework is not available in Delphi Prism. This makes porting even more difficult because classic Delphi code relies heavily on the VCL.
== References ==Oxygene_(%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) ru:Oxygene]
Cite error: Invalid
parameter "group" is allowed only.
<references />, or
<references group="..." />