Avatar of marc

by

Sneak Peek: Inline Interface Implementations in Prism XE2 and Cooper

July 27, 2011 in .NET, Cooper, Oxygene, Prism

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

Some Background

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.

Example

So how might this work? Let’s have a look at the following (fictitious) type:

type
  IButtonDelegate = interface
    method OnCLick(aButton: Button);
    method OnGetHoverHint(aButton: Button): String;
  end;
 
  Button = class
  private
  public
    property Caption: String;
    property Events: IButtonDelegate;
  end;

We have a button class, along with a delegate interface that defines its events. Whenever the button is clicked or needs to show a hint, it will check if something has been assigned to the Events property, and if yes calls the necessary method.

Now, let’s see how we would go and implement this using the new inline interfaces feature:

begin
  var b := new Button;
  var lCaptionWhenClicked := 'You clicked me!';
  b.Events := new interface IButtonDelegate(OnClick := method(b2: Button) 
                                                       begin 
                                                         b2.Caption := lCaptionWhenClicked; 
                                                       end, 
                                            OnGetHoverHint := b2 -> 'This is the '+b2.Caption+' button');
end.

First, you see we are using the new new interface syntax, which works symmetrical to new class for anonymous classes. In essence, this does create an anonymous class, one that implements the IButtonDelegate interface. Inside the parenthesis, we provide a implementation for some or all of the methods that are needed by the interface. These can be in anonymous method format (as OnClick shows in the example) or as lambdas (as OnGetHoverHint illustrates). We could also use a reference to an existing method, using the @ operator.

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 := method 
            beginend;

So that’s inline interface implementations. The feature will be incredibly useful when using Project “Cooper” and working with Java-style frameworks and APIs, but we can also see it coming in handy on the .NET/Mono platform in many cases – not necessarily as a replacement for multi-cast events, but in more traditional “delegate” scenarios.

Stay Tuned for More

Read more about Delphi Prism at remobjects.com/prism.
Read more about Project Cooper, currently in beta, at remobjects.com/cooper.

2 responses to Sneak Peek: Inline Interface Implementations in Prism XE2 and Cooper

  1. “our event keyword is not supported when compiling for the Java platform”

    Can’t you just automatically inline a delegate for every event requested, instead of simply not supporting it? Plus, don’t keep too close to the java language, there is stuff the JVM allows that java itself doesn’t. Maybe the JRuby/Scala/Closure guys can shime some ideas if you get trouble somewhere for that.

    • we could probably make “pretend events” yes, but they would be out of sync with what Java (platform) libraries are designed like. Just like Oxygene/.NET tried to stay true to the .NET framework and to not push Delphiisms into the language, we want Cooper to be a true citizen on the Java platform.

      .NET events worked different than Delphi ones – and we chose to do events the .NET way; Java again does events different, and we feel we’d be missing our goal if we tried to force .NEt multi-cast event paradigms into Java.