15

I was under the impression that assignment was not possible inside a lambda expression. E.g., the following (admittedly not very useful) code

Expression<Action<int, int>> expr = (x, y) => y = x;

Produces the compiler error

An expression tree may not contain an assignment operator

And yet, according to Microsoft's documentation, one can programmatically create an assignment expression using Expression.Assign. Unless I am mistaken, the following code produces an equivalent Expression:

ParameterExpression xparam = Expression.Parameter(typeof(int), "x");
ParameterExpression yparam = Expression.Parameter(typeof(int), "y");
BinaryExpression body = Expression.Assign(yparam, xparam);
var expr = Expression.Lambda<Action<int, int>>(body, xparam, yparam);
var cexpr = expr.Compile();

In this case, the compiler does not complain. I feel like I am missing some important distinction here.

Dan Barowy
  • 2,270
  • 24
  • 35
  • 2
    The compiler error is misleading. It means that the compiler cannot generate the code for you to create an assignment (so that LINQ providers are not all required to support it). You are free to create whatever you want. – Gabe May 30 '13 at 22:00
  • 1
    @Gabe you should answerify that comment. – Dan May 30 '13 at 22:01

2 Answers2

16

usr's answer is correct; to expand on it somewhat:

You are not missing an important distinction, you are missing an important dimension: time.

If you look at the documentation carefully you'll note that the Assign node was added in .NET 4.0.

Expression trees were added to C# 3.0, which shipped with .NET 3.5.

The team that owns the expression tree library has added many features to it since .NET 3.5 shipped. Using those features to allow more expressions to be in an expression tree in the C# language did not make the cut for C# 4.0 or C# 5.0. There's no reason to not do the feature; it's a perfectly sensible feature. But the language designers do not require a reason to not do a feature; they require a reason to spend the budget on a feature.

In this case, richer expression trees in C# simply did not make it high enough on the priority list. If you'd like that feature to be higher priority then you can open an issue on connect.microsoft.com and request it. Your request is more likely to be implemented if you include a compelling scenario for the feature.

Gabe
  • 84,912
  • 12
  • 139
  • 238
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    OK, this clarifies things. The reason I asked is that it appeared to be the case that only side-effect-free lambdas were possible. But as I look through Expression types, I see many operations which change state. I don't have a compelling use-case yet for the un-lambda-able Expression types, but it would be nice to be able to enforce purity for user-defined lambdas in general. – Dan Barowy May 31 '13 at 17:45
  • @DanBarowy: Expression trees *in the initial release* were designed for side effects free operations because that is what LINQ needed, though they were not 100% strict; for example, a method that has a ref parameter can be expressed in an expression tree. – Eric Lippert May 31 '13 at 18:13
10

You are not misunderstanding anything. C# is intentionally restrictive in the kinds of expression trees it can generate for you. There's no principled reason why it couldn't have that feature. It just wasn't invested in. (Creating features takes away resources. Would you rather have async/await or expression tree statements? Clearly the first option is more useful.).

You also cannot generate other statements like if or while although they are in the expression tree API starting with .NET 4. (You can construct and compile complex control flows with expression trees now).

usr
  • 168,620
  • 35
  • 240
  • 369