Tuesday, November 20, 2007

Stating the obvious

Should we always state the obvious? Interface types can only declare methods, properties and events (and assertions, since we're talking about Freya!). Fields, in any case, are not allowed inside an interface declaration.
Properties, however, are designed most of the times to resemble fields. Why should we stick to the property keyword when declaring properties for an interface type?
IScene = interface
Sampler: ISampler; readonly;
Camera: ICamera; readonly;
Root: IShape; readonly;
Lights: Array[ILight]; readonly;

method Render: PixelMap;
method Render(Row, Col: Integer): Pixel;
end
Of course, if you feel uneasy about dropping the keyword, you can still use it. Notice that there's no possible confusion, even with the declaration of Lights: that's a property returning an array, not an array property.
By the way, the above code fragment shows another omission: that of the final semicolon after the type declaration. Freya syntax has been relaxed to use optional semicolons in several places: after the end keyword in a complex type declaration and after the statement block in a method implementation. We're not going as far as Eiffel, where semicolons are optional almost everywhere, but our new syntax makes easier manual code translation from C# into Freya.

Labels: , , ,

Sunday, January 15, 2006

More on interface delegations

As I explained here, Freya allows the programmer to implement an interface type by delegating the implementation of methods from the interface to an instance of an already existing implementation. This trick is borrowed from Delphi, and it's an effective and easy technique for reusing interface implementations. Then, I used this example:
// WARNING: THE SYNTAX HAS CHANGED!!!
public

Foo = class(IEnumerable)
end;

implementation for Foo is

// A private instance field.
var Items: array of String := ['Freya', 'rules'];

// Just an implementation detail!
interface IEnumerable is Items;

end.
Our Foo class must implement the IEnumerable interface type, and it does it by delegating the implementation to a string array; all array types implement that interface, don't they? The delegation member contains a mention to the private field Items... but our real interest is the value stored in that field and, since our field is already initialized, it's highly probable that Items won't be referenced from other methods in this class. Why, then, should we need to declare Items at all?
This is a new alternative technique for delegating interface implementation:
implementation for Foo is

interface IEnumerable := ['Freya', 'rules!'];

end.
Now we can merge all what we need for the delegation in a single clause! Just think in all that can be done with this new feature. We have used a string list in our example, but it will be more common to find a regular constructor call as initializer:
implementation for Foo is

interface IEnumerator := new DriveEnumerator;

end.
In short, now we have two kinds of delegation clauses. One of them refers to a field or property in the same class. In this case, you can initialize the field or property in a constructor, or using a field or property initializer. The second and shorter form assigns directly a value in the delegation clause using an initializer. In this case, the compiler declares a hidden field inside the class and takes care of its initialization.

Labels:

Thursday, April 28, 2005

Implementing interface mappings

Freya has three techniques for implementing interface types:
  1. Implicit implementation: a public method in the class with the proper signature.
  2. Explicit implementation: an implicitly private method, with a compound name including the interface type name and the interface method name, just as in C#.
  3. Implementation by delegation: this is a feature borrowed from Delphi. It’s a simple but effective technique for reusing implementations, and it makes easy to change the behavior of an instance by plugging a different implementation, at runtime.
I'll show you an example of implementation by delegation:
using System, System.Collections;
public
// All Foo features are private
Foo = class(IEnumerable)
end;

implementation for Foo is
// A private instance field.
var Items: Array[String] = ['Freya', 'rules'];

// Just an implementation detail!
interface IEnumerable = Items;

end.
In this example, all calls to methods from IEnumerable methods are dispatched to the implementation of IEnumerable already available in Items. This is possible because there’s an implicit conversion from any array type to IEnumerable.
Native Delphi implemented this feature with a clever trick, by modifying the typecast operation. Our current implementation is probably not as efficient as native Delphi’s one, but it’s easy to code. When an interface delegation is found by the compiler, it synthesizes the required methods in the implementing class. Since these are very short methods, chances are high that the CIL loader will translate them as inline method calls.
We are trying another complementary solution: whenever possible, those method thunks call the target implementation using “tail calls”. Tail calls are supported by the CIL through an instruction prefix that can precede the “call” and “callvirt” operation codes. This prefix instructs the CLR to discard the current stack frame before jumping to the target method. There are no guarantees that this hint will be honored by the CIL loader, however. We still have to run the corresponding benchmarks before deciding the best translation for this useful feature.
Update: I didn't realize then, but tail calls have no effect when performed on virtual methods, so, after some tests, this "optimization" was discarded.
By the way, tail calls are only generated when the method signature does not include any reference or out parameters. That’s because a reference could point to a variable in the current stack frame, so the CLR has no way to verify whether a given call is safe or not. When all parameters are passed by value, tail calls are considered a safe operation.

Labels: