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: , , ,

Tuesday, February 13, 2007

Field-based properties

Freya already supports field-based properties. If you declare a property, but you don't provide an implementation, the compiler adds automatically a hidden field and implements the property using the new field. Even if the property is declared as read only, you can assign values to the hidden field using the property name, as long as your code is located inside the declaring class or inside another class nested in the declaring class.
I was declaring the hidden field as private, but I have realized that it's better to declare it as an internal field, so any class compiled inside the same assembly could access the field instead of the property. Of course, if the property is read only, any other class still can not write on the field. Another constraint has to do with virtual properties: if the property is declared as virtual, it's not safe to reference the field instead of the property.

Labels: , ,

Tuesday, March 28, 2006

Indexers

I had postponed any decision on Freya indexers until I could find a better model for representing name overloading in the symbol table. The original data structure was borrowed from Blue, and it was based in a clever trick: each context table contained a "group symbol" entry, which associated a name like WriteLine to the list of overloaded methods. At the same time, each of these methods was included independently. Since the context table is a kind of hash dictionary, method names were "decorated" or mangled, adding information from the parameter types.
I started with a version of Blue without indexers, and that's the reason why the symbol table only considered overloading for methods, but not for properties. There was another problem with explicit and implicit user defined conversions. The raw op_Implicit and op_Explicit methods violate one important rule in Freya and C#: they cannot be distinguished by the parameters signature! Suppose you write this in C#:
public static operator explicit double(Complex);
public static operator explicit float(Complex);
They translate to something like this:
public static double op_Explicit(Complex);
public static float op_Explicit(Complex);
Both methods have identical parameter lists, and they only differ in their return types. Of course, this is forbidden in C# and Freya... but is supported by the CLR. But the decorated parameter trick was inappropiate for representing this situation.
I have solved the problem by only including the group name for user defined conversions and indexers. Probably, there's no reason for including decorated method names in the hash table, but I won't mess right now with such a far reaching change in the compiler.
Finally, Freya has full functional indexers, following Visual Basic.NET. The reason:
  1. The VB model is the most general.
  2. Surprisingly, you can access secondary indexers from a C# application.
  3. So far, I haven't discovered any important drawback in the VB model.
I have also added lifted operators to Freya: these are automatic extensions for predefined and user operators for dealing with nullable types, and they imitate the behavior of SQL operators when they act on null values.

Labels: ,

Saturday, May 14, 2005

On properties and events

The simplest way to declare an event in C#, only requires from you to provide the event declaration:
event EventHandler Click;
Then, the C# compiler adds the implementation:
  1. A private field of the corresponding delegate type.
  2. A method called add_Click for adding handlers to the delegate chain.
  3. A symmetric remove_Click method, for removing handlers.
Outside the declaring class, the only operations you can perform with the event is adding and removing event handlers, using the now famous shortcut:
myClass.Click += myClickHandler;
By the way, you can’t fire the event from outside the declaring class! That’s encapsulation. However, things are different inside the class. The compiler generates a private field, and it doesn’t let you access that field... apparently. Actually, whenever you mention the event identifier from inside the declaring class, the compiler handles the identifier as if it were the private field. You’re free to do with the event identifier whatever it’s allowed with a delegate type field.
Events in Freya are identical to C# events. We also implemented a variant of this trick to be used with properties (credits belong to the authors of Chrome, another .NET language inspired in Delphi). When you’re designing a class, you often declare fields that should be transformed later into properties… or, on the contrary, you start with properties that map directly to a naked field with the same type. How much code do you need to write in this very simple and frequent case? A lot, if you’re using C#. You must declare the field, then the property and most of the times, both access methods.
In Freya, you only need to declare the property:
property Caption: string;
If we don’t provide an implementation for Caption, Freya will generate a private field and two access methods with proper signatures. Outside the declaring class, you will only see the property. However, inside the class, any reference to the property will be translated as a reference to the underlying field. In our previous example, Caption is a read/write property. If you want a read only property, you only need to add the readonly keyword to the declaration:
property Caption: string; readonly;
You could even declare an initializer for the property:
property Caption: string := 'Form1';
That’s an internal access, of course, and the compiler just moves the initializer to the private field. Of course, you can also “initialize a property” when the property has an explicit setter, but then, the initialization code calls the setter method when creating a new object instance.
As a final remark, we allow grouping related properties in a single declaration:
property X, Y: Double := 0;
The initializer applies to both properties, of course, and it should be evaluated only once.

Labels: , ,