Events in lambda expressions - C# compiler bug? - c#

I was looking at using a lamba expression to allow events to be wired up in a strongly typed manner, but with a listener in the middle, e.g. given the following classes
class Producer
{
public event EventHandler MyEvent;
}
class Consumer
{
public void MyHandler(object sender, EventArgs e) { /* ... */ }
}
class Listener
{
public static void WireUp<TProducer, TConsumer>(
Expression<Action<TProducer, TConsumer>> expr) { /* ... */ }
}
An event would be wired up as:
Listener.WireUp<Producer, Consumer>((p, c) => p.MyEvent += c.MyHandler);
However this gives a compiler error:
CS0832: An expression tree may not contain an assignment operator
Now at first this seems reasonable, particularly after reading the explanation about why expression trees cannot contain assignments. However, in spite of the C# syntax, the += is not an assignment, it is a call to the Producer::add_MyEvent method, as we can see from the CIL that is produced if we just wire the event up normally:
L_0001: newobj instance void LambdaEvents.Producer::.ctor()
L_0007: newobj instance void LambdaEvents.Consumer::.ctor()
L_000f: ldftn instance void LambdaEvents.Consumer::MyHandler(object, class [mscorlib]System.EventArgs)
L_0015: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
L_001a: callvirt instance void LambdaEvents.Producer::add_MyEvent(class [mscorlib]System.EventHandler)
So it looks to me like this is a compiler bug as it's complaining about assignments not being allowed, but there is no assignment taking place, just a method call. Or am I missing something...?
Edit:
Please note that the question is "Is this behaviour a compiler bug?". Sorry if I wasn't clear about what I was asking.
Edit 2
After reading Inferis' answer, where he says "at that point the += is considered to be assignment" this does make some sense, because at this point the compiler arguably doesn't know that it's going to be turned into CIL.
However I am not permitted to write the explicit method call form:
Listener.WireUp<Producer, Consumer>(
(p, c) => p.add_MyEvent(new EventHandler(c.MyHandler)));
Gives:
CS0571: 'Producer.MyEvent.add': cannot explicitly call operator or accessor
So, I guess the question comes down to what += actually means in the context of C# events. Does it mean "call the add method for this event" or does it mean "add to this event in an as-yet undefined manner". If it's the former then this appears to me to be a compiler bug, whereas if it's the latter then it's somewhat unintuitive but arguably not a bug. Thoughts?

In the spec, section 7.16.3, the += and -= operators are called "Event assignment" which certainly makes it sound like an assignment operator. The very fact that it's within section 7.16 ("Assignment operators") is a pretty big hint :) From that point of view, the compiler error makes sense.
However, I agree that it is overly restrictive as it's perfectly possible for an expression tree to represent the functionality given by the lambda expression.
I suspect the language designers went for the "slightly more restrictive but more consistent in operator description" approach, at the expense of situations like this, I'm afraid.

+= is an assignment, no matter what it does (e.g. add an event). From the parser point of view, it is still an assignment.
Did you try
Listener.WireUp<Producer, Consumer>((p, c) => { p.MyEvent += c.MyHandler; } );

Actually, as far as the compiler is concerned at that point, it is an assignment.
The += operator is overloaded, but the compiler doesn't care about that at it's point. After all, you're generating an expression through the lambda (which, at one point will be compiled to actual code) and no real code.
So what the compiler does is say: create an expression in where you add c.MyHandler to the current value of p.MyEvent and store the changed value back into p.MyEvent. And so you're actually doing an assignment, even if in the end you aren't.
Is there a reason you want the WireUp method to take an expression and not just an Action?

Why do you want to use the Expression class? Change Expression<Action<TProducer, TConsumer>> in your code to simply Action<TProducer, TConsumer> and all should work as you want. What you're doing here is forcing the compiler to treat the lambda expression as an expression tree rather than a delegate, and an expression tree indeed cannot contain such assignments (it's treated as an assignment because you're using the += operator I believe). Now, a lambda expression can be converted into either form (as stated on [MSDN][1]). By simply using a delegate (that's all the Action class is), such "assignments" are perfectly valid. I may have misunderstood the problem here (perhaps there is a specific reason why you need to use an expression tree?), but it does seem like the solution is fortunately this simple!
Edit: Right, I understand your problem a bit better now from the comment. Is there any reason you can't just pass p.MyEvent and c.MyHandler as arguments to the WireUp method and attach the event handler within the WireUp method (to me this also seems better from a design point of view)... would that not eliminate the need for an expression tree? I think it's best if you avoid expression trees anyway, as they tend to be rather slow compared to delegates.

I think the problem is, that apart from the Expression<TDelegate> object, the expression tree is not statically typed from the perspective of the compiler. MethodCallExpression and friends do not expose static typing information.
Even though the compiler knows all the types in the expression, this information is thrown away when converting the lambda expression to an expression tree. (Have a look at the code generate for expression trees)
I would nonetheless consider submitting this to microsoft.

Related

In c#, why can't lambdas have extensions?

In Unity, here's a category in c#,
public static class HandyExtensions
{
public static IEnumerator Tweeng( this System.Action<float> v, float d )
{
while (..)
{
..
v( 13f*t );
yield return null;
}
v(13f);
}
Compiles fine!
But if you try to use it,
yield return StartCoroutine(
( (x)=>laser=x ).Tweeng(3.141f)
);
this saddening error appears:
Assets/scripts/...cs(116,34): error CS0023: The .' operator cannot be applied to operand of typeanonymous method'
I have tears about this.
How could c# let us down?
Surely there's a way to call "on" a lambda like that, for an extension?
BTW the workaround is to go 3.14f.Tweeng((x)=>laser=x) but it's not as cool.
I'm sorry this saddens you, but this choice was made deliberately by the language design team. The code which evaluates whether a given extension method is valid requires that the receiver have a clear type, and lambda expressions do not have a type.
There was some debate on this point, but ultimately it was decided that (1) the proposed feature is potentially confusing or error-prone if typeless expressions like lambdas, method groups and null literals get to be receivers of extension methods, and (2) the proposed feature is not at all necessary to make LINQ work. We were very constrained in our schedules when implementing C# 3 and anything that was not necessary to make LINQ work was cut. It was much easier to design, implement and test the feature of "don't allow lambdas as receivers" than to have to consider all the potentially odd cases where a lambda, method group or null was being used as the receiver.
As others have said, you can simply cast the lambda, or put it in a variable and then use the variable as the receiver.
Alternatively, as you note, you could consider using the float as the receiver in your specific example.
Quell your tears fair Joe, let not despair drive you from your dream! If you explicitly cast it, it should work.
Try:
yield return StartCoroutine(
((System.Action<float>)( (x)=>laser=x )).Tweeng(3.141f)
);

Why are lambdas convertible to expressions but method groups are not?

LINQPad example:
void Main()
{
One(i => PrintInteger(i));
One(PrintInteger);
Two(i => PrintInteger(i));
// Two(PrintInteger); - won't compile
}
static void One(Action<int> a)
{
a(1);
}
static void Two(Expression<Action<int>> e)
{
e.Compile()(2);
}
static void PrintInteger(int i)
{
Console.WriteLine(i);
}
Uncommenting the Two(PrintInteger); line results in an error:
cannot convert from 'method group' to
'System.Linq.Expressions.Expression<System.Action<int>>'
This is similar to Convert Method Group to Expression, but I'm interested in the "why." I understand that Features cost money, time and effort; I'm wondering if there's a more interesting explanation.
Because, in order to get the expression tree, we need a representation of the method in (uncompiled) source form. Lambda expressions are locally available in the source code and therefore are always available uncompiled. But methods may not be from inside the current assembly, and may thus be available only in compiled form.
Granted, the C# compiler could decompile the assembly’s IL code to retrieve an expression tree but as you mentioned, implementing feature costs money, this particular feature isn’t trivial, and the benefits are unclear.
There is no reason in principle. It could be done this way. The compiler could just create the lambda by itself before converting it (this is obviously always possible - it knows the exact method being called so it can just create a lambda from its parameters).
There is one catch, though. The name of the parameter of your lambda is normally hard-coded into the IL being generated. If there is no lambda, there is no name. But the compiler could either create a dummy name or reuse the names of the method being called (they are always available in the .NET assembly format).
Why didn't the C# team decide to enable this? The only reason that comes to mind is that they wanted to spend their time elsewhere. I applaud them for that decision. I'd rather have LINQ or async than this obscure feature.
In the One example, you are implicitly creating an Action<int> delegate. It's the same as:
One( new Action<int>( PrintInteger ) );
I believe this is in the language to improve the syntax for subscribing to events.
The same thing doesn't happen for Expression<T>, which is why your second example doesn't compile.
EDIT :
It's called a "method group conversion". It's in the C# spec - section 6.6
An implicit conversion (§6.1) exists from a method group (§7.1) to a compatible delegate type

Why are lambda expressions not "interned"?

Strings are reference types, but they are immutable. This allows for them to be interned by the compiler; everywhere the same string literal appears, the same object may be referenced.
Delegates are also immutable reference types. (Adding a method to a multicast delegate using the += operator constitutes assignment; that's not mutability.) And, like, strings, there is a "literal" way to represent a delegate in code, using a lambda expression, e.g.:
Func<int> func = () => 5;
The right-hand side of that statement is an expression whose type is Func<int>; but nowhere am I explicitly invoking the Func<int> constructor (nor is an implicit conversion happening). So I view this as essentially a literal. Am I mistaken about my definition of "literal" here?
Regardless, here's my question. If I have two variables for, say, the Func<int> type, and I assign identical lambda expressions to both:
Func<int> x = () => 5;
Func<int> y = () => 5;
...what's preventing the compiler from treating these as the same Func<int> object?
I ask because section 6.5.1 of the C# 4.0 language specification clearly states:
Conversions of semantically identical
anonymous functions with the same
(possibly empty) set of captured outer
variable instances to the same
delegate types are permitted (but not
required) to return the same delegate
instance. The term semantically
identical is used here to mean that
execution of the anonymous functions
will, in all cases, produce the same
effects given the same arguments.
This surprised me when I read it; if this behavior is explicitly allowed, I would have expected for it to be implemented. But it appears not to be. This has in fact gotten a lot of developers into trouble, esp. when lambda expressions have been used to attach event handlers successfully without being able to remove them. For example:
class EventSender
{
public event EventHandler Event;
public void Send()
{
EventHandler handler = this.Event;
if (handler != null) { handler(this, EventArgs.Empty); }
}
}
class Program
{
static string _message = "Hello, world!";
static void Main()
{
var sender = new EventSender();
sender.Event += (obj, args) => Console.WriteLine(_message);
sender.Send();
// Unless I'm mistaken, this lambda expression is semantically identical
// to the one above. However, the handler is not removed, indicating
// that a different delegate instance is constructed.
sender.Event -= (obj, args) => Console.WriteLine(_message);
// This prints "Hello, world!" again.
sender.Send();
}
}
Is there any reason why this behavior—one delegate instance for semantically identical anonymous methods—is not implemented?
You're mistaken to call it a literal, IMO. It's just an expression which is convertible to a delegate type.
Now as for the "interning" part - some lambda expressions are cached , in that for one single lambda expression, sometimes a single instance can be created and reused however often that line of code is encountered. Some are not treated that way: it usually depends on whether the lambda expression captures any non-static variables (whether that's via "this" or local to the method).
Here's an example of this caching:
using System;
class Program
{
static void Main()
{
Action first = GetFirstAction();
first -= GetFirstAction();
Console.WriteLine(first == null); // Prints True
Action second = GetSecondAction();
second -= GetSecondAction();
Console.WriteLine(second == null); // Prints False
}
static Action GetFirstAction()
{
return () => Console.WriteLine("First");
}
static Action GetSecondAction()
{
int i = 0;
return () => Console.WriteLine("Second " + i);
}
}
In this case we can see that the first action was cached (or at least, two equal delegates were produced, and in fact Reflector shows that it really is cached in a static field). The second action created two unequal instances of Action for the two calls to GetSecondAction, which is why "second" is non-null at the end.
Interning lambdas which appear in different places in the code but with the same source code is a different matter. I suspect it would be quite complex to do this properly (after all, the same source code can mean different things in different places) and I would certainly not want to rely on it taking place. If it's not going to be worth relying on, and it's a lot of work to get right for the compiler team, I don't think it's the best way they could be spending their time.
Is there any reason why this behavior—one delegate instance for semantically identical anonymous methods—is not implemented?
Yes. Because spending time on a tricky optimization that benefits almost no one takes time away from designing, implementing, testing and maintaining features that do benefit people.
The other answers bring up good points. Mine really doesn't have to do with anything technical - Every feature starts out with -100 points.
In general, there is no distinction between string variables which refer to the same String instance, versus two variables which refer to different strings that happen to contain the same sequence of characters. The same is not true of delegates.
Suppose I have two delegates, assigned to two different lambda expressions. I then subscribe both delegates to an event handler, and unsubscribe one. What should be the result?
It would be useful if there were a way in vb or C# to designate that an anonymous method or lambda which does not make reference to Me/this should be regarded as a static method, producing a single delegate which could be reused throughout the life of the application. There is no syntax to indicate that, however, and for the compiler to decide to have different lambda expressions return the same instance would be a potentially breaking change.
EDIT I guess the spec allows it, even though it could be a potentially breaking change if any code were to rely upon the instances being distinct.
This is allowed because the C# team cannot control this. They heavily rely on the implementation details of delegates (CLR + BCL) and the JIT compiler's optimizer. There already is quite a proliferation of CLR and jitter implementations right now and there is little reason to assume that's going to end. The CLI spec is very light on rules about delegates, not nearly strong enough to ensure all these different teams will end up with an implementation that guarantees that delegate object equality is consistent. Not in the least because that would hamper future innovation. There's lots to optimize here.
Lambdas can't be interned because they use an object to contain the captured local variables. And this instance is different every time you you construct the delegate.

Why do parentheses around lambda statement cause syntax error?

I'm looking for a good explanation why one piece of code fails to compile and the other compiles just fine.
Fails:
richTextBox1.Invoke(new MethodInvoker((() => { richTextBox1.AppendText("test"); })));
Gives the error
Method name expected
on the opening parenthesis right after MethodInvoker(. Apparently, I can't wrap my lambda statements in parentheses.
Compiles:
richTextBox1.Invoke(new MethodInvoker(() => { richTextBox1.AppendText("test"); }));
The questions is - why?
I always took it for granted that I could wrap any method param in parentheses if I wanted but apparently that's not the case with lambda expressions. I understand that they are somewhat special, but I still can't see a good reason for this. Maybe I don't understand something about the syntax. I would really like to get it.
By the way, this presents in VS2008, .NET 3.5 SP1, I haven't tested it in VS2010 and .NET 4 yet.
It's not a lambda expression, it's a parenthesized expression that contains a lambda expression. Therefore, the node for this parameter in the abstract syntax tree for this method invocation would be a parenthesized expression, and not a lambda expression as required by the specification. This is why.
There are other places where the Microsoft C# compiler does violate the specification and accept such an expression even though it shouldn't (per the specification) but this is not one of them.
The relevant section of the specification is §6.5.
You are mistaken in the premise that you have written a “method param”. The construct you have created is not a method call, you have written a delegate creation expression (see the C# specification, section 7.6.10.5), which is supposed to have a single argument, which must be either
a method group,
an anonymous function or
a value of either the compile time type dynamic or a delegate-type.
In your case, it is not a method group (the error message is hinting that a method name is expected there), nor an anonymous function (since it is an expression which “somewhere inside” contains an anonymous function), nor a value of the said types.
If you wrote a method invokation, you could, indeed, wrap the parameter in parentheses, even if it contains a lambda expression:
void Method(Action action)
{
}
...
Method((() => { Console.WriteLine("OK"); }));
Because the compiler expects ()=>{} inside the Invoke() method and in the first example it does not find it. Everything within the parenthesis is evaluated first returning a single object, at which case the compiler expects the reference to a delegate.
Edited
I have solved the same problem with this Extension method:
public delegate void EmptyHandler();
public static void SafeCall(this Control control, EmptyHandler method)
{
if (control.InvokeRequired)
{
control.Invoke(method);
}
else
{
method();
}
}
So you can call
RichTextBox rtb = new RichRextBox();
...
rtb.SafeCall( ()=> rtb.AppendText("test") );

Is there a case where delegate syntax is preferred over lambda expression for anonymous methods?

With the advent of new features like lambda expressions (inline code), does it mean we dont have to use delegates or anonymous methods anymore? In almost all the samples I have seen, it is for rewriting using the new syntax.
Any place where we still have to use delegates and lambda expressions won't work?
Yes there are places where directly using anonymous delegates and lambda expressions won't work.
If a method takes an untyped Delegate then the compiler doesn't know what to resolve the anonymous delegate/lambda expression to and you will get a compiler error.
public static void Invoke(Delegate d)
{
d.DynamicInvoke();
}
static void Main(string[] args)
{
// fails
Invoke(() => Console.WriteLine("Test"));
// works
Invoke(new Action(() => Console.WriteLine("Test")));
Console.ReadKey();
}
The failing line of code will get the compiler error "Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type".
lambda is shortcut for anonymous delegate, but you will always be using delegates. the delegate specifies the methods signature. you can just do this:
delegate(int i) { Console.WriteLine(i.ToString()) }
can be replaced with
f => Console.WriteLine(f.ToString())
Lambda expression is not (and was not meant to be) a silver bullet that would replace (hide) delegates. It is great with small local things like:
List<string> names = GetNames();
names.ForEach(Console.WriteLine);
it makes code more readable thus simple to understand.
It makes code shorter thus less work for us ;)
On the other hand it is very simple to misuse them. Long or/and complex lambda expressions are tending to be:
Hard to understand for new developers
Less object oriented
Much harder to read
So “does it mean we don’t have to use delegates or anonymous methods anymore?” No – use Lambda expression where you win time/readability otherwise consider using delegates.
One not so big advantage for the older delegate syntax is that you need not specify the parameters if you dont use it in the method body. From msdn
There is one case in which an anonymous method provides functionality
not found in lambda expressions. Anonymous methods enable you to omit
the parameter list. This means that an anonymous method can be
converted to delegates with a variety of signatures. This is not
possible with lambda expressions.
For example you can do:
Action<int> a = delegate { }; //takes 1 argument, but not specified on the RHS
While this fails:
Action<int> a = => { }; //omitted parameter, doesnt compile.
This technique mostly comes handy when writing event-handlers, like:
button.onClicked += delegate { Console.WriteLine("clicked"); };
This is not a strong advantage. It's better to adopt the newer syntax always imho.
Delegate have two meanings in C#.
The keyword delegate can be used to define a function signature type. This is usually used when defininge the signature of higher-order functions, i.e. functions that take other functions as arguments. This use of delegate is still relevant.
The delegate keyword can also be used to define an inline anonymous function. In the case where the function is just a single expression, the lambda syntax is a simpler alternative.
Lambda expressions are just "syntactic sugar", the compiler will generate appropriate delegates for you. You can investigate this by using Lutz Roeder's Reflector.
Lamda's are just syntactic sugar for delegates, they are not just inline, you can do the following:
s.Find(a =>
{
if (a.StartsWith("H"))
return a.Equals("HI");
else
return !a.Equals("FOO");
});
And delegates are still used when defining events, or when you have lots of arguments and want to actually strongly type the method being called.

Categories