While catching up with a friend for (a very geeky) lunch the other day, a few ideas crystalised into another idea for the next version of C#.
The lambda expression syntax introduced in C# 3.0 is a brilliant step forward from the anonymous delegates of C# 2.0,
but one thing has always irked me - that a lambda expression with no parameters needs to be written this way:
() => expression
Clearly, you need specific syntax to identify a lambda expression, but is this really the best they could do?
I have a suggestion to make: For a parameterless lambda expression, why can’t we just write a block, surrounded by
braces. So, instead of these:
Action a = () => { MyVoidMethod(); };
Func<bool> b = () => { return MyBoolFunction(); }
We should be able to write
Action a = { MyVoidMethod(); };
Func<bool> b = { return MyBoolFunction(); }
(And, yes, I’m aware that there are simpler ways to write those first examples, ways that are still valid C#. Bear with me, there is a point to my rambling.)
Now, let’s throw a new piece of parameter syntax sugar into the mix. Hopefully you’ll be aware of the params
keyword
that allows you to write methods that take a variable number of parameters:
void Promote(params Person[] peopleToPromote) { … }
void Demo()
{
Promote( fred, wilma, barney, betty);
}
You can only use the params
keyword for the last parameter - the compiler will throw an error if you put it somewhere
else, or if the type given is not an array.
Let’s introduce a new keyword, block
that can only be used for the last parameters of the method, and only if those
parameter types are delegates with no parameters. The purpose of this parameter is to allow callers to put the
implementation of the block following the apparent method call, instead of within it.
If we take both of these ideas, we can change the code we write from this:
void Context(string label, Action action) { … }
void Demo()
{
Context("Doing a Demo", () => { PerformDemo(); });
}
Into this
void Context(string label, block Action action) { … }
void Demo()
{
Context("Doing a Demo")
{
PerformDemo();
};
}
A little bit of syntactic sugar has given us a nice way to craft apparent C# extensions, that work along the lines of
the existing using
statement.
But, wait, you say - when you described the block
keyword, you used the word parameters - what happens when you
have multiple block
parameters in your method signature?
I’m glad you asked. ;-) In line with the way that named parameters work in C# 4.0, I suggest each block should be prefixed by the name of the parameter being supplied. How would this look?
First, we declare the method itself - perhaps one to support writing transactional programs:
void Transaction(string label, block Action action, block Action commit) { … }
void Demo()
{
Transaction("A demo transaction")
action
{
…
}
commit
{
…
};
}
Or perhaps, one that that forms part of a “design by contract” API:
void Contract(string context, block Action requires,
block Action execute, block Action ensures) { … }
void Demo()
{
Transaction("A demo transaction")
requires
{
…
}
execute
{
…
}
ensures
{
…
};
}
So, what does this bit of syntactic sugar give us? Roll your own language extensions.
There are a few obvious ways to enhance this - such as allowing blocks to break out delegates that take parameters, but I’ll leave those as an exercise for the reader.
Comments
blog comments powered by Disqus