Sunday, July 08, 2007

Be constructive

We have already seen how useful can be expression based method implementations. Is there anything similar for constructors? Constructors have no return value, so they cannot directly benefit from expression based implementations... but it turns out there's a surprisingly similar feature at our reach.
In a sense, a constructor can be viewed as a static function (a method returning some value). The returned value is, of course, a new instance from the class the constructor belongs. In any case, there are a couple of constraints for constructors that regular methods have not: the return type must always be the same, inside a given class, and the returned instance must always be a new instance.
Note: It could make sense to remove the latter restriction. It's an important part of the contract for languages with explicit memory deallocation. Now think how you must implement an instance cache for a given class: since you cannot overload the new operator as in classic C++, you must search all creation expressions along the whole application to substitute them with method calls.
Given the previous constraints, and the fact that constructor calls are functional calls, we can find the equivalent to expression-based implementations: chained calls to sibling or parent constructors... a feature that was there all the time:
Stack = class[X]
private
Items: Array[X];
Count: Integer;
public
constructor(Capacity: Integer);
begin
Items := new Array[X](Capacity);
end;

constructor : Self(128);

// ...
end;
It's true it looks so different from regular expression-based implementations, but it's a historical consequence: chaining has been available in C++ from long time ago. The only novelty is that you can omit the whole method block from that point on.
It's recommendable to write always this kind of "bodiless" chaining in the class declaration, instead of using an implementation section. Neither C# nor Freya supports default parameter values, so it's very frequent to find a handful of constructors in a given type, each of them removing some parameters from the signature's tail. We can use chaining to implement all of them, except the first:
Metal = sealed class(IMaterial)
public
constructor
(Color: Pixel;
MinRefl, MaxRefl, Diffuse: Double;
PhongAmount, PhongSize: Double);

constructor(Color: Pixel;
MinRefl, MaxRefl, Diffuse: Double) :
Self(Color, MinRefl, MaxRefl, Diffuse, 0, 1);
constructor(Color: Pixel;
MinRefl, MaxRefl: Double) :
Self(Color, MinRefl, MaxRefl, 1, 0, 1);
constructor(Color: Pixel; MinRefl: Double) :
Self(Color, MinRefl, 1, 1, 0, 1);
constructor(Color: Pixel) :
Self(Color, 0.1, 1, 1, 0, 1);
end;
There's a second related question: is there any similar feature for iterators? I have an affirmative answer, but the syntactic details still need some boiling...

Though it's not an official Freya feature, it could also make sense to bring back another old C++ feature: field initialization in constructors. We could have written the previously shown Stack constructors like this:
// This is not Freya... yet...
constructor(Capacity: Integer)
: Items(new Array[X](Capacity));
constructor
: Self(128);
Of course, this enhances the expressivity of chaining, but that's not the main point. The main reason to bring this feature back has to do with programming by contract: this kind of field initialization may be necessary for implementing not nullable reference types, as in Spec#.

Labels: , , ,

Friday, January 05, 2007

Collection initializers

Freya have another new feature borrowed from C# 3.0: collection initializers.
var L := new List[Integer]![1, 2, 3, 4];
As you can see, an array literal can be appended to the creation of any class implementing the generic ICollection[T] interface type. But, this time, the array literal doesn't generates an array at runtime. Instead, for each item in the literal, a call to the method Add, from the collection, is generated.
In order to realize why we need collection initializers, you must weight the alternative method:
var L := new List[Integer]([1, 2, 3, 4]);
In this case, the array literal is passed as a parameter to the constructor call. However, the parameter is declared as IEnumerable[T]. Can you see what it means? A temporal array must be generated and initialized, item by item. Then, the array must be casted as a IEnumerable[T] reference, which will be passed to the constructor. Inside the constructor, GetEnumerator is called, and a second temporal object is created. Finally, a loop is performed, in order to add an item for each enumerated item.

Labels: ,

Monday, January 02, 2006

Object initializers

Take a look at this code:
// C# 3.0
var a = new Point { X = 0, Y = 1 };
This fragment has been copied from the C# 3.0 specification preview. According to that document, the above instruction should be interpreted as:
// C# 3.0
var a = new Point();
a.X = 0;
a.Y = 1;
So, we have a "normal" instance construction followed by property or field assignments. Does this remind you any other existing C# feature? Sure, that's how custom attributes are instantiated. Custom attributes mix positional parameters corresponding to constructor parameters, and named parameters, which must be translated as post-construction assignments. We could extend the syntax from custom attributes to object creation:
// A proposal
var a = new Point(X = 0, Y = 1);
Of course: I know object initializers were proposed for C# 3.0 as part of the support for anonymous types. In C# 3.o, you could drop the "constructor part" like this:
// Anonymous types in C# 3.0
var p1 = new {
Name = "Lawnmower", Price = 495.00 };
But then, why not this?
// Anonymous types in C# 3.0: a proposal
var p1 = new(
Name = "Lawnmower", Price = 495.00 );
Is this a good idea? I still have to check the 3.0 proposal, to see whether there is any other reason to prefer the curly braces initializers (nested initializers, for instance). In any case, I think it's better for Freya to adopt the "custom attribute initialization syntax" for object initializers: the literal translation of C#'s curly braces would be a begin/end pair. So, we could initialize a Point object in Freya this way:
// A proposal for Freya 1.0
var p := new Point(X := 0, Y :=0);
var tb := new DataTable(
'Customers', CaseSensitive := true);
How do you like it?

Labels: ,

Thursday, May 12, 2005

Creation statements

A minor but useful enhancement: take a look to this common code written in C#:
Dictionary<int,string> d =
new Dictionary<int,string>();
Why do we have to write the type name twice? Well, put the blame in polymorphism. In our example, the declared type of the local variable and the type of the created instance are the same. But we could have specified a class descending from Dictionary, if any, in the right side expression. Easy, huh?
However, most of the times both types will be the same. Could we avoid the duplication? If you're using Freya, the answer is YES:
var
d: Dictionary[Integer,String];
begin
new d;
// Now, a parameterized constructor:
new d(1024);
end;
A useful time saver, isn't it?

Updated: We have dropped the new statement after the publication of the first draft for C# 3.0. Now we have variable declarations with implicit types, as in the C# 3.0 proposal.

Labels: