views:

1741

answers:

5

Why does this lambda expression not compile?

Action a = () => throw new InvalidOperationException();

Conjecture is fine, but I would really appreciate references to the C# language specification or other documentation.

And yes, I know that the following is valid and will compile:

Action a = () => { throw new InvalidOperationException(); };

The context where I would use something like this is described on this blog post.

A: 

All the references I can find, from here:

http://msdn.microsoft.com/en-us/library/ms364047(VS.80).aspx#cs3spec_topic4

show that you have two options:

Action a = () => { throw new InvalidOperationException(); };

or

Action a = () => throw new InvalidOperationException()

Note the missing ; on the end. Yes, it makes no sense to me either. The examples they give in the spec are:

x => x + 1                     // Implicitly typed, expression body
x => { return x + 1; }         // Implicitly typed, statement body
(int x) => x + 1               // Explicitly typed, expression body
(int x) => { return x + 1; }   // Explicitly typed, statement body
(x, y) => x * y               // Multiple parameters
() => Console.WriteLine()      // No parameters

Dunno how much help that is - I can't tell what context you are using it in, and not putting a ; on the end makes no sense in C#

the difference may be that it's an expression body - not a statement - if it doesn't have the {}. Which means that your throw is not valid there, as it's a statement, not an expression!

Nic Wise
The no semicolon makes sense in the context of the lambda body, but not as a statement where you are assigning to an Action.The context I would use this in is alluded to in http://jacobcarpenter.wordpress.com/2008/10/06/c-compiler-eccentricity-of-the-day-throwing-lambda/
Jacob Carpenter
I can guarantee you that Action a = () => throw new InvalidOperationException() does NOT compile.
Will
The compiler still expects a ; at the end of the line.
Will
+10  A: 

Here's my take:

throw is a statement, not an expression.

And the reference:

12.3.3.11 Throw statements

For a statement stmt of the form

throw expr;

the definite assignment state of v at the beginning of expr is the same as the definite assignment state of v at the beginning of stmt.

To explain the essence perhaps one should think about what an expression implies within the C# lambda construct. It is simply syntactic sugar for:

delegate () { return XXX; }

where XXX is an expression

leppie
But you can't ever say return Console.WriteLine("something")
Jacob Carpenter
A: 

You can't return or throw from an un-scoped lambda.

Think of it this way... If you don't provide a {}, the compiler determines what your implicit return value is. When you throw from within the lambda, there is no return value. You're not even returning void. Why the compiler team didn't handle this situation, I don't know.

Will
+10  A: 

Hmm. I've got an answer, but it's not great.

I don't believe that there's a "throw" expression. There's a throw statement, but not just an expression. Compare this with "Console.WriteLine()" which is a method invocation expression with a void type.

As a parallel, you can't have a switch statement, or an if statement etc as the body of a lambda on its own. You can only have an expression or a block (section 7.14).

Is that any help?

Jon Skeet
That's what I said a few minutes back. You just need to ask yourself: "What does a statement evaluate to?" the answer being nothing.
leppie
Well, a call to Console.WriteLine doesn't evaluate to anything either, unless you count "void"... but yes, we were certainly thinking along the same lines, hence my +1 of your answer :)
Jon Skeet
That is helpful. I still wonder though why assignment to a closure works, since I read "num = 0" as a statement.
Jacob Carpenter
Console.WriteLine does match the return type though :)
leppie
"num = 0" is an assignment expression. "num=0;" is a statement.
Jon Skeet
Huhh. That's a subtle distinction. Thanks.
Jacob Carpenter
A: 

Not a big surprise. Lambda expressions are an aspect of functional programming. Exceptions are an aspect of procedural programming. The C# mesh between the two styles of programming isn't perfect.

Justice
No, it's not the side-effect aspect which is the problem here. You can't have an "if" statement even if it doesn't have side-effects, but you *can* have an assignment expression which is a side-effect. It's a statement/expression distinction.
Jon Skeet
Right. In pure functional programming, which is sort of the model which lambda expressions is going for, there are only expressions, no statements (statements are mimicked with monadic expressions). It's a a little tricky to get a statement-based language to play well with pure expressions.
Justice