C# 4, part 5: Other bits and bobs which probably don't merit inclusion
Okay, I know I said that part 4 would be the last part in this series... but since then I've not only thought about iterator block parameter checking, but a few other things. Some of these I simply forgot about before, and some I hadn't thought of yet. I'm not sure any of these are actually worthy of inclusion, but they may provoke further thought.
Tuple returns
I've been reading Programming Erlang and I suspect that being able to return tuples (i.e. multiple values, strongly typed but without an overall predefined type) would be a good thing. For instance, in a tuple-returning world, int.TryParse could be redesigned to return both the true/false and the parsed value. It could have a signature like this:
public static (int, bool) TryParse(string text)
... and then be called like this:
int value;
bool parsed;
(value, parsed) = int.TryParse("Foo");
Now, a few things to work out:
How do we ignore values we're not interested in?
Part of the problem with out parameters is that sometimes you don't actually care about the value - but you still have to declare and pass in a parameter. Suppose we could use ? as a placeholder for "I don't care". (This is _ in Erlang pattern matching, IIRC. Same kind of business.)
What could you do with a tuple?
We could potentially make tuples first class citizens, so that you could declare variables of that type, a bit like anonymous types, but with anonymous property names as well, used just for matching later. Or we could force matching at the point of method call, which would restrict the use a bit further but leave less other rules to be worked out.
Either way, I'd hope to be able to set either fields or properties by parameter matching.
What's the value of the overall expression?
This really depends on the answer to the previous question. If tuples are first class types, then the result of the expression would normally be the tuple itself. However, I wonder whether there's more that can be done. For instance, thinking about our TryParse example, it's useful to be able to write (currently):
if (int.TryParse("Foo", out value))
{
...
}
Suppose we were able to designate one of the matched elements of the tuple to be the expression result, e.g. using _ to be slightly Perl-like:
if ((value, _) = int.TryParse("Foo"))
{
...
}
Would that be worth doing?
More information required...
I suspect that people who know more about the use of tuples in other languages would be able to say more about this. Some overlap with anonymous types is clearly relevant too, and would need to be carefully considered. I'm not wedded to any of the syntax shown above, of course - I'm just interested in how/where it could be useful.
Named method/constructor arguments
One of the features I like about F# is that you can specify the names of arguments, without worrying about the order. This means that it becomes even more important to name methods appropriately, but it would make method calls with many parameters simpler to read. Currently it's common practice to use one parameter per line and a comment to indicate the use, e.g.
foo.Complicated(10,
"bar",
x => x+1,
3.5
);
In fact, this example is relatively simple because all the parameter types are different - look at the more complicated overloads of Enumerable.GroupBy for rather more hellish examples. It's incredibly ugly, and the compiler isn't able to check anything. Now suppose we could instead write:
foo.Complicated(maxElements = 10,
collectionName = "bar",
step = x => x+1,
load = 3.5);
Personally I think that's clearer and less error-prone. The arguments could be reordered with few issues, and the compiler could check that we really were using the right parameter names. One potential issue is in terms of side-effects, where evaluating one argument had a side-effect which affected the evaluation of another argument. At that point reordering is a breaking change. I suspect the compiler would need to stick to the specified textual order, and then rework things on the stack as required to get the appropriate order for the method call. A bit nasty.
Event handler subscription in object initializers
I only thought of this one today, when coming up with an example for a screencast on object initializers. I suspect most uses of object initializers will be to with custom classes (although I recently used them for XmlWriterSettings to great effect) which would make the screencast harder to understand. I was wondering what common framework classes had lots of writable properties, and I hit on the idea of building a UI. It shouldn't surprise me that this works quite nicely, but you can build up a hierarchical UI quite pleasantly. For example:
Form form = new Form
{
Size = new Size(300, 300),
Controls =
{
new Button
{
Location = new Point(10, 10),
Text = "Hello",
},
new ListBox
{
Location = new Point(10, 50),
Items =
{
"First",
"Second",
"Third"
}
}
}
};
Application.Run(form);
This is somewhat reminiscent of Groovy builders (and no doubt many other things, of course). However, one thing you can't currently do is attach an event handler in an object initializer. The obvious syntax would be something like:
new Button
{
Location = new Point(10, 10),
Text = "Hello",
Click += (sender, args) => Save()
}
where I happen to have used a lambda expression, but didn't need to - a normal method group conversion or any other way of constructing a delegate would have done just as well.
I mailed the C# team about this, and although it's been considered before it's really not useful in many situations. However, the syntax has been left open - there's no other use of += within object initializers, so it could always be revisited if someone comes up with a killer pattern.
Immutable object initialization
I've been thinking about this partly as a result of object initialization in general, and the previous point about named arguments. As has been noted before, C# doesn't really help you to build immutable objects - either as from the point of view of building the type, or then instantiating it. Basically you've got the constructor call, and that's it. A static method could set private properties and then return the object for popsicle immutability, but it still feels slightly grim.
Someone (possibly Marc Gravell - not sure) suggested to me that there ought to be some way of indicating when an object initializer had finished. At the time I think I rejected the idea, but now I like it. There's already the ISupportInitialize interface, but that feels slightly too heavy to me - in particular, it has two methods rather than just one. What I think could be nice would be:
- A new interface with a single
CompleteInitialization method. - Readonly automatic properties which would either make the property only writable during a constructor call if the new interface weren't implemented or would insert an execution-time check that
CompleteInitialization hadn't been called already. - I'd anticipate the C# compiler implementing the new interface itself automatically in some way which supported inheritance reasonably, unless specifically implemented by the developer.
- Members other than constructors couldn't set readonly automatic properties on
this, to avoid accidents. - The CLR should have some interaction so it knew which fields it could treat as being readonly after initialization had been completed.
- Object initializers would call
CompleteInitialization automatically at the end of the block.
It's a bit messy, and I'm sure I haven't thought of everything - but I suspect something along these lines would be a good idea at some point. It's reminiscent of an earlier wacky idea I had which went further, but this would be specifically to support immutability. Without it, complex immutable types end up with nightmarish constructor calls.
Conclusion
So there we have it - some relatively half-baked ideas which will hopefully provoke a bit more thought - both from readers and myself. It's interesting to note that aside from event subscription, they all have a fair number of questions and complexity around them, which is off-putting to start with. I would feel more comfortable about event subscription being added than any of the others, because it's relatively simple and independent. The others feel like more dangerous features - even if they're more useful too.