Today, I would like to talk about another new language feature that is new in Oxygene 5. This particular feature was mainly added for Project “Cooper” to fill a need on the Java platform, but it is also available on .NET. The feature is Inline Interface Implementations
Java does not use multicast events like .NET, but instead employs the more traditional delegate model. Classes that fire events or have callbacks usually come with a companion delegate interface that defines any methods that the class wants to call back on. In fact, our event keyword is not supported when compiling for the Java platform.
Of course, implementing an interface in Oxygene is easy, but with the nature of events and callbacks, you might not always want to implement the delegate interface on your main object. For example, what if your form holds two buttons? You can’t really define a global OnClick method on your form and have it handle clicks from either button. That’d be silly. Of course you create a separate helper object, but that’s clumsy and a lot of work.
The Java language allows interfaces to be implemented inline, and we brought that feature over to Oxygene, for all platforms.
So how might this work? Let’s have a look at the following (fictitious) type:
|type IButtonDelegate =interfacemethod OnCLick(aButton: Button);method OnGetHoverHint(aButton: Button): String;end; Button =classprivatepublicproperty Caption: String;property Events: IButtonDelegate;end;|
Now, let’s see how we would go and implement this using the new inline interfaces feature:
|beginvar b :=new Button;var lCaptionWhenClicked :='You clicked me!'; b.Events:=newinterface IButtonDelegate(OnClick :=method(b2: Button)begin b2.Caption:= lCaptionWhenClicked;end, OnGetHoverHint := b2 -> 'This is the '+b2.Caption+' button');end.|
There are two things of note worth mentioning here: For one, just like regular anonymous methods, our interface implementations have full access to the surrounding code. Our event handlers can access the local lCaptionWhenClicked variable; they could also access self or any members of the containing object. For another, while in this case we implement all (whopping two) members of the interface, that is not necessary. You only need to implement the members you need, empty implementations will automatically be provided by the complier for any method you skip.
As a special convenience, the compiler will treat interfaces with a single method as assignment compatible with regular single method pointers. So if you encounter a delegate interface with only a single method, you can skip the whole “new interface” syntax and simply assign a method pointer, just as you would with a regular .NET delegate:
|c.Events:=methodbegin … end;|