CSharp vs. Oxygene

From The Elements Wiki
Jump to: navigation, search

This is an Oxygene Language topic
 

Oxygene Language: Intro | Structured Overview | Grammar | Keywords | Functions


The obvious differences between Oxygene and C# is the of course Object Pascal based syntax, which is very attractive for developers skilled in other Object Pascal dialects, such as Delphi, FreePascal, or other Pascal dialects. However, the language adds a wide range of other extremely useful enhancements as well:

See also Java vs. Oxygene.

The following is a list of language features that are available in Oxygene and not available in C#:

Compiler Feature
Description
Named indexed properties

C# can only access the default indexed properties. In Oxygene, you can define and use other indexed properties using their name.

Sets

A set is a collection of ordinal values of the same type. Sets are a convenient way of storing and accessing values that belong together.

Parallel Support

Supply the async directive on a method and it will automatically run in a separate thread. If the method returns values, these will become futures.

Colon Operator

This is essential to our nullable support, but it is also a surprisingly useful feature for general coding. Basically, instead of using "." to access members and get a NullReferenceException if they are nil, use ":" and the call will be skipped for nil (and the result will be nil itself). For example:

// only call dispose if the interface is implemented.
IDisposable(SomeObject):Dispose;
// access the 3rd parent of a control, where any level might be nil.
x := Button:Parent:Parent:Parent;
Inline Property Accessors

Define simple properties within the class declaration, without any extra setters/getters.

property Foo: String; // local field is implied;
property Right: Int32 read Left+Width; // reader expression is provided in line.
Class Contracts
  1. you can define "public invariants" for the class, which will be enforced every time any non-private method exits to validate the classes internal structure (you can also define "private invariants" that will be enforced when private ones exit, as well). Invariants are a list of boolean expressions that must all be "true" for the class to be in a valid state.
  2. you can add "require" sections before the method body, and "ensure" ones after, to define pre and post conditions. Again, these are boolean statements that will be checked to be true.
Class References

Define "class of X" types and virtual class methods (similar to Delphi for Win32).

"implies" operator

This is mostly helpful for invariants or pre/post-conditions. Basically, the second part only "needs" to be true if the first is; if the first is false, the entire expression is true. this sounds odd, but consider

require
   assigned(Customer) implies Customer.CreditRatio > 5;

this translates too

require
   (NOT assigned(Customer)) OR (Customer.CreditRatio > 5);

the above is much more readable.

"case type of"

Write a switch/case statement that executes different cases depending on the TYPE of a certain object, i.e.

case type MyControl of:
  Edit: // do something
  Button: // do something else
end;
Property Notifications

These save a lot of boilerplate code. Attach the "notify" keyword to a property as directive (like "virtual"), and the compiler generates all the infrastructure and interfaces needed for property notifications to work (in C#, you'll need to implement getters/setters, add interfaces to the class, etc).

Enhanced Nullable Types

Unlike C#, the Oxygene compiler provides full support for nullable types. You can call their members and use them in expressions; there's extensive support for nullable expressions - if any part that contributes to an arithmetic expression is "nullable", the whole expression becomes nullable. if any part IS null, the whole expression becomes null. For example:

x: nullable Int32;
y: Int;
var a := x+y; // result is a nullable Int32;
var b := 5*x; // if x is null, so is b.
improved 'for each' loop
for each matching x: Button in Controls do    // only run loop for buttons
// use i to count; also type of x is inferred automatically
// from type of "Controls", if its a generic enum
for each x in Controls index i do    
'locked' directive

The locked directive allows methods, events and properties to be declared implicitly thread safe.

Extended Constructor Calls

Set properties as part of the constructor call. This is especially useful if you're not assigning to a local ref. For example:

Controls.Add(new Button(Width := 100; Height := 50));

without this, you; would need a temp var for the button.

This is now possible with C# 3.0.

Boolean Double Comparison
if 0 <= x < Count then //...
Iteration delegation

The yield keyword supports delegation of the iterator to a second sequence.

Empty Methods

Supply the 'empty' directive on a method's interface declaration and you dont need to define the empty method body.

Exception Filters

Catch selective exceptions not only based on type, but also based on any arbitrary condition (supported by VB.NET, but not C#).

raising/firing events

You can specify the visibility for raising/firing events. In C#, only the class that defines an event can fire it (from outside you can only add/remove handlers). In Oxygene, you can write the following and descendants can fire the event:

public
  event Foo:EventHandler protected raise;