Aside from the vast amount of New Language Features compared to Delphi that Oxygene brings to Object Pascal, it also provides some minor cleanup of idiosyncrasies to make the language more consistent and a better citizen on the (semi-)managed platforms. This topic describes these "cleanups" in more detail.
True Namespace Support
Oxygene has full support for Namespaces. As such, it does away with the unit keyword used in Delphi, and each source file starts with the keyword instead, optionally followed by a namespace name. All types declared in a unit are part of the same namespace (unless the type declaration provides a full alternative namespace), and multiple source files can and usually will contribute to the same namespace — in fact, it is even common for small to medium projects to place all their types into a single namespace.
The clause syntax persists as in Delphi, but instead of listing units to be used, it will list the namespaces that you want to be in scope for the current source file. Any types declared in either the current namespace or a namespace that is "used" will be visible within the source file without specifying the full namespace.
It is important to distinguish between Namespaces and
References. Using a namespace only brings types
into scope that are already known to the compiler, so that they can be
identified by their short name. References added to the project (.dlls
on .NET, .jar files on Java and on Cocoa) in turn give the compiler a
list of places to find types in. Often, there's a direct mapping between
a reference and a namespace (UIkit.fx, for example, contains the
classes in the
UIKit namespace), but sometimes that is not the case.
Read more on Namespaces and References.
0-Based Object-Oriented Unicode String
In Oxygene, the standard
String type maps to the platform's default string class, which contains immutable, zero-based unicode strings. On
.NET that is
Foundation.NSString and on
Because Strings are true objects, they provide member methods and
properties you can call to perform string manipulations, mostly
obsoleting helper libraries such as Delphi's StrUtils unit. Another
important consideration is that, because strings are regular objects,
the language differentiates between a
nil string reference vs. an empty
Oxygene allows the use of either single (
'Hello') or double
"World") quotes for string literal declarations.
Proper Private/Protected Visibility
In Oxygene, the
protected Visibility Levels truly have the visibility implied by their names: private members are truly private to
the individual class; protected members are only accessible to
descendant classes. In Delphi, both of these keywords allow unchecked
access to private and protected members of all classes in the same unit
— which is unclean.
Recent versions of Delphi have introduced new strict private and
strict protected visibility sections that mimic what Oxygene's
protected visibility types do out of the box.
unit or protected visibility can be used to obtain an
effect similar to Delphi's interpretation of private/protected.
Delphi also supports a published visibility type that behaves mostly identical to public. This visibility is not supported or needed in Oxygene.
Nameless Constructors and the
Oxygene uses nameless constructors (and optionally constructors with Cocoa's with* naming convention) instead of Delphi's convention of using regular method names, commonly starting with Create. This goes along with the operator, which is used for instantiating objects.
The use of Create is not supported in Oxygene by default, neither for declaring constructors, nor for calling them.
No Destructors, but Finalizers
As a slightly related concept, but not 100% comparable to destructors, Oxygene supports Finalizers to allow objects to perform cleanup when they are released. Unlike Delphi's destructors, finalizers will be automatically called by the runtime as needed, and will/should never be called explicitly.
While still supported, Oxygene deprecates the procedure and function
keywords and favors the
method keyword to be used for all method declarations.
The reasoning for this is two-fold. For one, Pascal traditionally calls things by their name — and Methods are something fundamentally different than the actual functions and procedural of pre-OOP procedural programming. For another, in modern Pascal it seems unnecessary and arbitrary to distinguish between methods that return a result and those that do not.
Oxygene employs the standard Pascal
:= assignment operator in two
places where Delphi uses the plain
Default values for method parameters are indicated using
:=, such as:
This is to emphasize that it's really a default assignment to the parameter that is happening here, not an expression of equality.
method Foo(a: Int32; b: String := 'default');
Similarly, fields, properties and local variables can be
pre-initialized using a
fMyField: Int32 := 5;syntax; differing from Delphi's
const fMyField: Int32 = 5syntax. Once again, the point is that the field is not a constant, but merely pre-initialized and that an assignment is being expressed, not an equality.
Oxygene continues to use
= for actual constant declarations, such as
const MY_CONST = 5;, as here a constant is declared to be
equal to a given value.
The syntax for so-called "typed consts" is supported, but members
defined with this syntax are pure constants and cannot be modified; in
const works the same whether a type is specified or not (symmetrical
to how it works to define a variable, whether a type is specified or omitted - a feature we call ).
Unsupported Member Modifiers
Delphi supports a plethora of method flags that are unnecessary or have no relevance on the platforms supported by Oxygene, and are thus not supported. These include:
safecallflags, used in Delphi to indicate the lower-level binary calling convention to use for the method, are not supported or necessary in Oxygene.
overloadflag is not supported or necessary in Oxygene, method overloading is supported by default.
deprecated"cross-platform" warning flags are not supported in Oxygene.
dynamickeyword, used by Delphi to indicate an alternative technique for method virtualization, is not supported in Oxygene.
reference tokeywords are not supported.
All of these keywords can be used (in most cases to be ignored) via the Delphi Compatibility Settings.
out in method calls
In Oxygene, when passing values by reference to a method declared with
out keyword, it is necessary to prefix the passed parameter with the
out keyword. This makes sure that it is obvious from the call
site that the parameter is passed by reference, and can be modified by
the called method.
In Oxygene for Cocoa, the
out keywords can also be
used to call framework APIs that are defined to take object pointers – which essentially are C's and Objective-C's way of passing by reference.
Recent versions of Delphi have begun implementing support for Generics, and the basic syntax for declaring and using them – via type parameters in angle brackets – is the same in Oxygene and Delphi. Unfortunately, while Delphi borrowed the basic syntax from Oxygene, which brought it to the Pascal landscape first, Embarcadero chose to use a different syntax for declaring Generic Constraints.
Oxygene uses the keyword and a rich syntax for declaring the various
different types of constraints, such as
is IFoo, or
has constructor. It does not support Delphi's constraint syntax.
Different behavior of the
In Oxygene, the
/ division operators always derive their result from the type of the input parameters. Dividing two integers will result in an integer; dividing floats will result in a float. This is consistent with how all other operators behave as well.
The "Use Delphi-compatible division operators" project option can be used to change this behavior. See Delphi Compatibility Settings for details.
Oxygene drops Delphi's inherently unsafe with construct and replaces
it with a new construct that forces the declaration of a new variable
name to access the scope of the
with clause. This preserves many of
the benefits of the
with feature as found in Delphi, without the
dangerous scope conflicts.
Of course, the Inline Variable Declarations support in Oxygene makes the new
with rarely used these days.
No initialization and finalization Sections
Oxygene does not provide support for initialization and finalization sections, nor any similar functionality because no concept exists on the underlying platforms that would allow to reliably reproduce the functionality provided by these features in Delphi - namely to execute particular code at startup or shutdown of the application.
Depending on your design goal, there are several avenues to consider for providing the necessary functionality. If the purpose of the initialization section is to initialize a type or types defined in the module, [Class Constructors](Class Constructors) might be an appropriate solution, and are available on all platforms. If you are trying to register types or information for later consumption, consider using Custom Attributes (on .NET and Java) or other infrastructure provided by the runtimes on all three platforms for querying available classes.
Delphi-style GUIDs in Interface Declarations
No Resource Strings
resourcestring keyword is not supported in Oxygene. Each of the platforms targeted by Oxygene has unique (and usually intuitive and simple to use) ways to deal with localized strings, but they are not tool-chain compatible with having resources strings defined in code.
Seefor platform-specific topics on how to deal with localization.
Pointers and "Unsafe" Code
As a managed environment, .NET and Java provide limited support for pointers and directly manipulating memory. In general, this is not a problem and most code that relies on pointers can, with a little effort, be rewritten to run fully managed and verifiable - this is the recommended approach.
On .NET, Oxygene supports writing so-called Unsafe
Code by setting the appropriate project option
and marking methods with the
unsafe keyword. The term "unsafe" here does not reflect that such code is
inherently bad or broken, just that it (potentially) performs memory
actions that cannot be verified as "safe" by the runtime. As such, the
runtime may impose restrictions on unsafe code, for example when running
applications from the network, in specific host environments, or in
other low-trust scenarios, such as on phones or on WinRT.
Where possible, unsafe code should be avoided, but the option is there if needed. Please refer to the Unsafe Code topic for more details on this.
On Cocoa, which we sometimes like to refer to as semi-managed, pointers and other code constructs common for "unmanaged" code are available.
On Java, "unsafe" code is not supported at all.
Interface Method Renaming
Delphi for Win32 uses the "
=" operator to implement interface methods
under a different name should conflicts arise, such as:
procedure MyFooBar; procedure IFoo.bar = MyFooBar; // maps the MyFooBar method to the IFoo interface
Oxygene does not provide this syntax, but uses the
implements keyword to achieve this
(and provide a lot more flexibility in the process). Refer to the Interface topic for more details.
Oxygene uses named parameters to initialize a record and class fields and properties.
var x := new MyRecord(Field1 := 'test', Field2 := 15.2)
This syntax works in both definition and in code blocks.
Delphi does not have a syntax for this that works inside blocks, but it does have one for constants:
const p: TPoint = (x: 15; y : 16);
This syntax is not supported in Oxygene.
- Oxygene does not allow access to the outer result variable from inside a nested local method.
- Oxygene does not allow you to re-declare a local variable in a nested method, if a variable of the same name is also declared in the outer method.
You are not allowed to compare Booleans with the
Oxygene requires the exact number of array parameters, as the array
defines when accessing array members. For an
array of array of integerit requires
MyArray[dim1][dim2], for an
array[0.., 0..] of Integerit requires the
- Variant records are not directly supported in Oxygene, except on Cocoa.
Inline Assembler Code
Since Oxygene compiles against many different target platforms,
including IL, JVM, x86, x64 and ARM, it does not provide support for the
asm keyword and inline assembler code.