<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx</link><description>[UPDATES below] A while back I described a kind of variance that we’ve supported since C# 2.0. When assigning a method group to a delegate type, such that both the selected method and the delegate target agree that their return type is a reference type,</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9808907</link><pubDate>Mon, 29 Jun 2009 23:33:03 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9808907</guid><dc:creator>luckylooke</dc:creator><description>&lt;p&gt;that's one deep post about the type system. I have never analyzed it in so much depth although i run into the problem before with action&amp;lt;int&amp;gt; (btw i allways wandered if int is the most commonly used type ever and i think it is) trying to do the same thing... The compiler yelled at me so I considered aaah void is not a supertype of int me bad, never even thinking about the stack&lt;/p&gt;
&lt;p&gt;now i am one thing smarter:)&lt;/p&gt;
&lt;p&gt;thanks for that&lt;/p&gt;
&lt;p&gt;luke&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9808909</link><pubDate>Mon, 29 Jun 2009 23:34:43 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9808909</guid><dc:creator>Pavel Minaev [MSFT]</dc:creator><description>&lt;p&gt;This seems like an implementation detail. In the end, the actual stack that is used when executing code is native stack, not IL stack - and it seems like CLR itself could insert cleanup calls for cases where a non-void method would be called via a void delegate.&lt;/p&gt;
&lt;p&gt;In fact, it seems that it wouldn't even need any cleanup on x86 for most cases, given that in native code the return value is just EAX for all primitives &amp;lt;= sizeof(int) and all reference types, which can be safely ignored. So it would only have to do additional setup for returning value types and such.&lt;/p&gt;
&lt;p&gt;Of course, when looked that way, it's not a C# limitation - it's a CLR limitation.&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9808945</link><pubDate>Tue, 30 Jun 2009 00:06:46 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9808945</guid><dc:creator>freeborn</dc:creator><description>&lt;p&gt;why not to translate it as &lt;/p&gt;
&lt;p&gt;Action&amp;lt;bool&amp;gt; action = x =&amp;gt; DoSomething(x);&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9808976</link><pubDate>Tue, 30 Jun 2009 00:38:34 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9808976</guid><dc:creator>Scott</dc:creator><description>&lt;p&gt;Another reason why the unit approach from ML used in F# is superior to the strange special-case void keyword =)&lt;/p&gt;
&lt;p&gt;It would allows syntax like C++'s &amp;quot;void return&amp;quot; too:&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;void foo() { return; }&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;void bar() { return foo(); }&lt;/p&gt;
&lt;p&gt;Whereas trying the same thing in C# gives error CS0127:&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;private void Foo()&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;private void Bar()&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return Foo();&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9808982</link><pubDate>Tue, 30 Jun 2009 00:45:47 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9808982</guid><dc:creator>configurator</dc:creator><description>&lt;P&gt;Not to nitpick, &lt;/P&gt;
&lt;DIV class=yellowbox&gt;
&lt;P&gt;Really? -- Eric&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;but shouldn't "member group" be "method group" in the sentence "When assigning a member group to a delegate type"? Also, in the same sentence you say "selected member" and I think that should be "selected method"&lt;/P&gt;
&lt;DIV class=yellowbox&gt;
&lt;P&gt;Yes. I make this mistake all the time; if you read back in the blog carefully you'll see that I call out this mistake here and there. The reason is because the specification says "method group" but the&amp;nbsp;structures in the compiler say "member group", and I read the compiler sources&amp;nbsp;more often than I read the spec. The data structures in the compiler can represent both methods and propery accessors, so "member group" is a reasonable name. I also have a bad habit of saying "type variable" when I mean "type parameter" for the same reason. The compiler and the spec were written at the same time; the compiler authors had to guess what the spec authors were going to choose as the jargon, and sometimes they guessed wrong. One of these days I'll clean all those up. -- Eric&lt;/P&gt;&lt;/DIV&gt;</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9809006</link><pubDate>Tue, 30 Jun 2009 01:44:17 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9809006</guid><dc:creator>CPDaniel</dc:creator><description>&lt;p&gt;It looks like you meant &lt;/p&gt;
&lt;p&gt;Action&amp;lt;void&amp;gt; action = DoSomething; &lt;/p&gt;
&lt;p&gt;where you wrote&lt;/p&gt;
&lt;p&gt;Action&amp;lt;bool&amp;gt; action = DoSomething;&lt;/p&gt;
&lt;p&gt;... as written, the code compiles just fine.&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9809038</link><pubDate>Tue, 30 Jun 2009 03:00:10 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9809038</guid><dc:creator>configurator</dc:creator><description>&lt;p&gt;CPDaniel: I don't have Visual Studio on me to check, but your comment puzzles me. He didn't mean Action&amp;lt;void&amp;gt; because that would mean a method that accepts a void parameter - which is invalid any way. Eric was talking about return value covariance, where the Func&amp;lt;bool, bool&amp;gt; becomes a Action&amp;lt;bool&amp;gt;, returning void instead of a bool.&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9809427</link><pubDate>Tue, 30 Jun 2009 11:58:40 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9809427</guid><dc:creator>jMarkP</dc:creator><description>&lt;P&gt;Fascinating as always :) Do you personally know of any good textbooks on this kind of thing - type systems, lambda calculus-y goodness? (The obvious SICP notwithstanding.) I'd love to flesh out my knowledge more on the theory behind languages and compilers.&lt;/P&gt;
&lt;DIV class=yellowbox&gt;
&lt;P&gt;"The Little Schemer" uses a fun question-and-answer approach to learning about CS theory via lambdas. But I recommend asking this question on stackoverflow; you'll get a lot higher quality of responses.&amp;nbsp;-- Eric&lt;/P&gt;&lt;/DIV&gt;</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9809733</link><pubDate>Tue, 30 Jun 2009 18:21:45 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9809733</guid><dc:creator>tb</dc:creator><description>&lt;p&gt;&amp;quot;Shouldn’t “void” be considered a supertype of all possible types for the purposes of covariant return type conversions from method groups to delegate types?&amp;quot;&lt;/p&gt;
&lt;p&gt;I see no reason why it should. It doesn't work for normal delegates, so I can't imagine why it should for Func&amp;lt;T&amp;gt; or Action&amp;lt;T&amp;gt;.&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9809887</link><pubDate>Tue, 30 Jun 2009 21:15:37 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9809887</guid><dc:creator>CPDaniel</dc:creator><description>&lt;p&gt;configurator:&lt;/p&gt;
&lt;p&gt;Yes, you're right - I wasn't paying attention! &amp;nbsp;The void return type is implied by the Action&amp;lt;T&amp;gt; generic delegate type.&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9809940</link><pubDate>Tue, 30 Jun 2009 22:15:41 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9809940</guid><dc:creator>Leopold Bushkin</dc:creator><description>&lt;p&gt;An interesting insight into the internals of how the compiler treats delegates and method group conversions to delegates. One question though, couldn't the compiler still allow this by automatically wrapping the method in a dynamically generated lambda, like so:&lt;/p&gt;
&lt;p&gt; &amp;nbsp;Action&amp;lt;bool&amp;gt; action = a =&amp;gt; DoSomething(b);&lt;/p&gt;
&lt;p&gt;Aside from the potential performance implications of the double indirection, is there a non-obvious reason why this could be problematic?&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9810185</link><pubDate>Wed, 01 Jul 2009 03:15:04 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9810185</guid><dc:creator>TheCPUWizard</dc:creator><description>&lt;p&gt;Leopold,&lt;/p&gt;
&lt;p&gt;As previously pointed out, it is not just a simple &amp;quot;double indirection&amp;quot;. Right in the middle code must exist which cleans up the return value of &amp;quot;DoSomething&amp;quot;. When using the technique explicitly, the developer should be aware of this. If the compiler implemented this &amp;quot;automatically&amp;quot; (appearing to be co-variant) then a &amp;quot;secret&amp;quot; overhead would exist. &lt;/p&gt;
&lt;p&gt;At least that is why I am glad that the compiler does not do this automatically....&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9810207</link><pubDate>Wed, 01 Jul 2009 04:04:08 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9810207</guid><dc:creator>Pavel Minaev [MSFT]</dc:creator><description>&lt;p&gt;A secret overhead already exists in many places in the JIT - for example, covariance and contravariance of delegate types when interfaces are involved cannot be free - it has to do some pointer shifting and such.&lt;/p&gt;
&lt;p&gt;Even C++ has that - compile a code sample with covariant return types of virtual functions with virtual base classes with /FA and see what dances the compiler has to do to make it all work...&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9810422</link><pubDate>Wed, 01 Jul 2009 09:42:19 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9810422</guid><dc:creator>configurator</dc:creator><description>&lt;p&gt;Eric, yes, really. How will I learn without asking these annoying questions all the time? Maybe I misunderstood something and a member group is actually something else? Now you've assured me that I understood your post correctly - and gave me a little insight into the compiler stuff.&lt;/p&gt;
&lt;p&gt;Do this member groups represent all properties (as in, a setter and a getter is the same group), or overloaded indexers, or something else that I haven't thought of? (I realize there can be a group with exactly one member and there would always be a group. I'm asking when is there more than one member in the group?)&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9810691</link><pubDate>Wed, 01 Jul 2009 13:29:20 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9810691</guid><dc:creator>Daniel Earwicker</dc:creator><description>&lt;p&gt;Very interesting, but I'd second freeborn's question. If a very simple boilerplate code shape can solve the problem, then the technical problem doesn't seem to explain the language design decision.&lt;/p&gt;
&lt;p&gt;But then, if a very simple boilerplate code shape can solve the problem, that's obviously going to push this problem down the list of priorities.&lt;/p&gt;
&lt;p&gt;At one point I was dead keen on the possibility that C# (or the CLR) would one day unify Func&amp;lt;void&amp;gt; and Action, making them just synonyms for exactly the same thing. I even tried to work the whole thing out, for my own amusement... but in fact it makes more sense for them to be separate. Action&amp;lt;...&amp;gt; is for things where order of execution is important because there may be side effects. Func&amp;lt;T, ...&amp;gt; is ideally for side-effect free, order-ignorant computations. So it may be better to keep them separate.&lt;/p&gt;
&lt;p&gt;Similar to the popular debate over a &amp;quot;ForEach&amp;quot; extension method, which also appealed to me until I read what Eric had to say about it. There is probably some value in making actions and functions &amp;quot;look&amp;quot; different in our code.&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9811081</link><pubDate>Wed, 01 Jul 2009 16:57:11 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9811081</guid><dc:creator>Leopold Bushkin</dc:creator><description>&lt;p&gt;@TheCPUWIzard, &lt;/p&gt;
&lt;p&gt;are you suggesting that using a lambda to wrap a function so that it's return value is ignored would cause the stack to not be correctly unwound? I don't believe this to be the case - I've been able to use this approach successfully in real-world code and I have never observed any negative consequences of doing so. &lt;/p&gt;
&lt;p&gt;However, if you are suggesting that there is a theoretical performance penalty to using this technique, then I would agree with that.&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9811144</link><pubDate>Wed, 01 Jul 2009 17:24:53 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9811144</guid><dc:creator>TheCPUWizard</dc:creator><description>&lt;p&gt;@Leopold,&lt;/p&gt;
&lt;p&gt;I definately did not intend to imply that where is anything &amp;quot;wrong&amp;quot; with using the wrapping technique. It is perfectly safe, valid, etc.&lt;/p&gt;
&lt;p&gt;What I am concerned about are implicit operations that may not do exactly what the developer (especially junior to mid-level) expects.&lt;/p&gt;
&lt;p&gt;When a construct (such as assigning an integer to a floating point) is extremely common, and the impact is well understood, then &amp;quot;true&amp;quot; implicit features are a great help.&lt;/p&gt;
&lt;p&gt;Next comes &amp;quot;explicit implicits&amp;quot; (such as declaring a conversion operation on a class) has control over what happens, and it can be implemented for specific cases where it is justified. These are also a great help and by their very nature have little risk of unexpected effects.&lt;/p&gt;
&lt;p&gt;[IMHO] it is when the compiler/language becomes very &amp;quot;liberal&amp;quot; with regard to &amp;quot;inherent implicits&amp;quot; that I see a risk (in terms of developers not truely comprehending shat is going on).&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9814652</link><pubDate>Thu, 02 Jul 2009 21:01:02 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9814652</guid><dc:creator>Pavel Minaev [MSFT]</dc:creator><description>&lt;p&gt;Overall I think the shortest answer why there's no covariance &amp;amp; contravariance for Void&amp;lt;-&amp;gt;T can be summed up as: &amp;quot;because Void is not a subtype or supertype of T&amp;quot;. One may argue whether _that_ limitation is reasonable or not, but it is what it is.&lt;/p&gt;
</description></item><item><title>re: The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx#9878708</link><pubDate>Fri, 21 Aug 2009 17:20:07 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9878708</guid><dc:creator>quetzalcoatl</dc:creator><description>&lt;p&gt;Eric: &amp;quot;every time we add a new conversion rule to the language we add breaking changes&amp;quot;&lt;/p&gt;
&lt;p&gt;Not true. if something would have not compiled, and now it will - this is NOT a breaking change.&lt;/p&gt;
&lt;p&gt;Pavel: &amp;quot;This seems like an implementation detail. In the end, the actual stack that is used when executing code is native stack, not IL stack - and it seems like CLR itself could insert cleanup calls for cases where a non-void method would be called via a void delegate.&amp;quot;&lt;/p&gt;
&lt;p&gt;I 100% agree. I started to write a reply to say this very thing. This is a CLR implementation detail, it is an side effect and limitation, not a the only right way that we all shall be ecstactic that the .net had chosen&lt;/p&gt;
&lt;p&gt;freeborn: &amp;quot;why not (..)&amp;quot;&lt;/p&gt;
&lt;p&gt;And by this limitation about void (and other nonexistent (co/contra)variances) everyone ends in handwriting sucha stubs like freeborn shown. A few characters about which that Eric is furious at the end of the post. You see, if you not include mechanism that will spit ot all the little methods, people WILL do it by hand, not find another bright solution.&lt;/p&gt;
&lt;p&gt;Btw. its really hard to find a brighter solution that Freeborn's, when you have ie. a framework events requesting return-void, and methods that return-bool, methods that ARE used ELSEWHERE in the code, and they must return that bool. What you do? For each such case, you write an adapter that looks like Freeborn's, or, you sculpt a generic that will envelop typical cases..&lt;/p&gt;
</description></item></channel></rss>