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
Next Post
Sharpening the Saw  18 Apr 2011
Prior Post
On Comments and Spam  01 Apr 2011
Related Posts
Queue Testing  08 Dec 2018
Creating Branching Nodes  01 Dec 2018
Two Dual Item Queues  24 Nov 2018
Simple Queues  17 Nov 2018
Enqueuing Values  10 Nov 2018
Dequeuing Values  03 Nov 2018
Designing the External API  27 Oct 2018
Introducing the Priority Queue  20 Oct 2018
A better approach to reflection  13 Oct 2018
Avoiding Magic Strings  06 Oct 2018
More csharp posts »
Archives
April 2011
2011