<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Fabulous Adventures In Coding</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/ericlippert/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/ericlippert/feed.xml</link>
    <description>Eric Lippert&amp;#039;s Erstwhile Blog</description>
    <lastBuildDate>Thu, 06 Aug 2015 07:02:35 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>A new fabulous adventure</title>
      <link>https://docs.microsoft.com/archive/blogs/ericlippert/a-new-fabulous-adventure</link>
      <pubDate>Thu, 29 Nov 2012 07:00:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Lippert]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericlippert/2012/11/29/a-new-fabulous-adventure/</guid>
      <description><![CDATA[Tomorrow, the 30th of November, 2012, is the first day of my fifth decade here on Earth, and my...]]></description>
      <content:encoded><![CDATA[<div class="mine">  <p>Tomorrow, the 30th of November, 2012, is the first day of my fifth decade here on Earth, and my last day at Microsoft. (*)</p>  <p>I've been working at Microsoft full-time since 1996 and had two years of internships before that. <strong>Microsoft is an awesome company.</strong> We do great work here: work that changes the way people interact with information in a fundamental way. And I in particular, have had the pleasure and the privilege to work on technologies that change how developers like me get their jobs done. There is no place doing better work on the design and implementation of real-world, production-strength programming languages that ship to millions of developers.</p>  <p>A number of those developers read this very blog, which I've been writing for nine years now. Sharing my fabulous adventures in coding with you all has been one of the most enjoyable parts of this job. I mean to continue writing it, but unfortunately, Microsoft's (entirely sensible) policy is that only full time employees get to post to MSDN blogs. I am therefore, effective right now, moving my blog to <a href="https://ericlippert.com">ericlippert.com</a>. <strong>Please subscribe to the RSS feed</strong>, which is at <a title="https://ericlippert.com/feed/" href="https://ericlippert.com/feed/">https://ericlippert.com/feed/</a>.&nbsp; (**)</p>  <p>I also intend to finally start "tweeting" occasionally; if you haven't already, please follow me on Twitter where I am <a href="https://twitter.com/ericlippert">@ericlippert</a>.</p>  <p>A number of people have asked me what motivated this decision. Of course any life decision of this magnitude has a lot of reasons behind it, but the biggest one is simply: I've been here for 40% of my entire life, I've been feeling for some time that it would be good to take on a new challenge, and an opportunity has arisen that is tailor-made to my skills and interests. I'll describe that new opportunity in <a href="https://ericlippert.com/2012/11/29/fabulous-adventures/">the first post on my new blog</a>. As you'll see, I am very pleased that it will still involve supporting the C# development community, just in a different way.</p>  <p>Were I to try to make a list of current and erstwhile coworkers to thank it would be extremely long and I would undoubtedly embarrass myself by omitting someone. I've had the opportunity to learn about programming languages and developer tools from literally hundreds of developers, testers, writers, editors, program managers, managers, mentors, architects, distinguished engineers and at least a couple of technical fellows. (***) <strong>Thank you all; I hope to continue to work with you in the future.</strong></p>  <p>And thanks to you all, who have been reading this blog these past nine years. Your comments, praise and always constructive criticism have helped me learn what customers need and helped everyone here shape C# into the amazing tool it is today. <strong>I hope we can continue sharing this adventure;</strong> see you at <a href="https://ericlippert.com">ericlippert.com</a>.</p>  <p>Eric Lippert</p>  <p><strong>UPDATE:</strong> Holy goodness, the outpouring here, on the new blog, on reddit, hacker news and twitter of both well-wishing and FUD is delightful for the former and distressing for the latter.</p>  <p>Regarding the former: thank you all for your kind thoughts; I appreciate it very much.</p>  <p>To dispel some of the rumours that are floating around regarding the latter:&nbsp;</p>  <p>(1) C#, Roslyn and .NET in general are doing fine; rumours of their deaths are greatly exaggerated. I certainly would not go to work on yet another C# static analyzer if I did not think there was a bright future to all of them, and to the Microsoft ecosystem in general. The C# language is in good hands; Anders and Mads are still deeply engaged in that process, and I am just one (albeit highly visible) member of a kick-ass team of dozens of people who are building Roslyn. I am leaving it in excellent hands and in excellent shape.&nbsp;</p>  <p>(2) As I said, this was a personal decision based on many factors; the main factor was a desire to pursue a new set of challenges that use my existing skill set. I certainly was not fired, and I look forward to having a close working relationship with the C# team in the future.</p>  <p>And finally:</p>  <p>(3) The first day of my first decade was the day I was born. So tomorrow being the first day of my fifth decade makes me 40, not 50.</p>  <p>Thank you again for your kind thoughts.</p>  <p>Eric</p>  <hr>  <p>(*) That timing is not coincidental.</p>  <p>(**) Since I will no longer have the ability to reply to comments, they are shut off as of now. If you have comments, please leave them on the new blog. Thanks!</p>  <p>(***) The most hilarious job title at Microsoft as far as I'm concerned.</p>  </div>]]></content:encoded>
    </item>
    <item>
      <title>Why is deriving a public class from an internal class illegal?</title>
      <link>https://docs.microsoft.com/archive/blogs/ericlippert/why-is-deriving-a-public-class-from-an-internal-class-illegal</link>
      <pubDate>Tue, 13 Nov 2012 09:32:26 GMT</pubDate>
      <dc:creator><![CDATA[Eric Lippert]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericlippert/2012/11/13/why-is-deriving-a-public-class-from-an-internal-class-illegal/</guid>
      <description><![CDATA[In C# it is illegal to declare a class D whose base class B is in any way less accessible than D....]]></description>
      <content:encoded><![CDATA[<div class="mine"> <p>In C# it is illegal to declare a class D whose base class B is in any way less accessible than D. I'm occasionally asked why that is. There are a number of reasons; today I'll start with a very specific scenario and then talk about a general philosophy. </p> <p>Suppose you and your coworker Alice are developing the code for assembly Foo, which you intend to be fully trusted by its users. Alice writes:</p> <p class="code">public class B<br>{<br>&nbsp; public void Dangerous() {...}<br>}</p> <p>And you write</p> <p class="code">public class D : B<br>{<br>... other stuff ...<br>}</p> <p>Later, Alice gets a security review from Bob, who points out that method Dangerous could be used as a component of an attack by partially-trusted code, and who further points out that customer scenarios do not actually require B to be used directly by customers in the first place; B is actually only being used as an implementation detail of other classes. So in keeping with the <a href="https://en.wikipedia.org/wiki/Principle_of_least_privilege">principle of least privilege</a>, Alice changes B to:</p> <p class="code">internal class B<br>{<br>&nbsp; public void Dangerous() {...}<br>}</p> <p>Alice need not change the accessibility of Dangerous, because of course "public" means "public to the people who can see the class in the first place".</p> <p>So now what should happen when Alice recompiles before she checks in this change? The C# compiler does not know if you, the author of class D, intended method Dangerous to be accessible by a user of public class D. On the one hand, it is a public method of a base class, and so it seems like it should be accessible. On the other hand, the fact that B is internal is evidence that Dangerous is supposed to be inaccessible outside the assembly. A basic design principle of C# is that <strong>when the intention is unclear, the compiler brings this fact to your attention by failing</strong>. The compiler is identifying yet another form of the Brittle Base Class Failure, which long-time readers know has <a href="https://blogs.msdn.com/b/ericlippert/archive/tags/brittle+base+classes/">shown up in numerous places in the design of C#</a>. </p> <p>Rather than simply making this change and hoping for the best, you and Alice need to sit down and talk about whether B really is a sensible base class of D; it seems plausible that either (1) D ought to be internal also, or (2) D ought to <a href="https://en.wikipedia.org/wiki/Composition_over_inheritance">favour composition over inheritance</a>. Which brings us to my more general point:</p> <p><strong>More generally</strong>: the inheritance <strong>mechanism</strong> is, <a href="https://blogs.msdn.com/b/ericlippert/archive/2011/09/19/inheritance-and-representation.aspx">as we've discussed before</a>, simply the fact that all heritable members of the base type are also members of the derived type. But the inheritance relationship <strong>semantics</strong> are intended to model the "is a kind of" relationship. It seems reasonable that if D is a kind of B, and D is accessible at a location, then B ought to be accessible at that location as well. It seems strange that you could only use the fact that "a Giraffe is a kind of Animal" at specific locations. </p> <p>In short, this rule of the language encourages you to use inheritance relationships to <strong>model the business domain semantics</strong> rather than as a <strong>mechanism for code reuse</strong>. </p> <p>Finally, I note that as an alternative, <strong>it <em>is</em> legal for a public class to implement an internal interface</strong>. In that scenario there is no danger of accidentally exposing dangerous functionality from the interface to the implementing type because of course the interface is not associated with any functionality in the first place; an interface is logically "abstract". Implementing an internal interface can be used as a mechanism that allows public components in the same assembly to communicate with each other over "back channels" that are not exposed to the public.</p></div>]]></content:encoded>
    </item>
    <item>
      <title>It's still essential!</title>
      <link>https://docs.microsoft.com/archive/blogs/ericlippert/its-still-essential</link>
      <pubDate>Fri, 09 Nov 2012 12:00:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Lippert]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericlippert/2012/11/09/its-still-essential/</guid>
      <description><![CDATA[I am pleased to announce that Essential C# 5.0 by Mark Michaelis, and, new for this edition, yours...]]></description>
      <content:encoded><![CDATA[<div class="mine"> <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/29/89/metablogapi/1715.EssentialCover_2.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-29-89-metablogapi/1715.EssentialCover_5F00_2.jpg"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="EssentialCover" border="0" alt="EssentialCover" align="left" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/29/89/metablogapi/4442.EssentialCover_thumb.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-29-89-metablogapi/4442.EssentialCover_5F00_thumb.jpg" width="240" height="240"></a>I am pleased to announce that <u>Essential C# 5.0</u> by Mark Michaelis, and, new for this edition, <em>yours truly</em>, is <a href="https://www.amazon.com/Essential-Edition-Microsoft-Windows-Development/dp/0321877586/">available for pre-order now</a>. It will be in stores in early December.</p> <p>As long-time readers of this blog know, I was one of the <a href="https://blogs.msdn.com/b/ericlippert/archive/2010/04/15/it-s-essential.aspx">technical editors</a> for <u>Essential C# 4.0</u> and <u>Essential C# 3.0</u>. Mark was kind enough to ask me if I would like to take a larger role in the process of updating the text for the new edition, which I gladly agreed to. There is no easier way to get a byline in a book than to assist with an update to a well-written series that you already know inside-out! Many thanks to Mark, as well as to Joan and everyone else at Addison-Wesley who made this process so smooth; you are all a pleasure to work with. Special thanks also to my coworker, C# specification guru Mads Torgersen, who wrote a very nice foreword for us, and to my colleague Stephen Toub who thoroughly reviewed the chapters dealing with asynchrony.</p></div>]]></content:encoded>
    </item>
    <item>
      <title>Dynamic contagion, part two</title>
      <link>https://docs.microsoft.com/archive/blogs/ericlippert/dynamic-contagion-part-two</link>
      <pubDate>Thu, 08 Nov 2012 06:43:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Lippert]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericlippert/2012/11/08/dynamic-contagion-part-two/</guid>
      <description><![CDATA[Last time I discussed how "dynamic" tends to spread through a program like a virus: if an...]]></description>
      <content:encoded><![CDATA[<div class="mine"> <p><a href="https://blogs.msdn.com/b/ericlippert/archive/2012/11/05/dynamic-contagion-part-one.aspx">Last time I discussed how "dynamic" tends to spread through a program like a virus</a>: if an expression of dynamic type "touches" another expression then that other expression often also becomes of dynamic type. Today I want to describe one of the least well understood aspects of method type inference, which also uses a contagion model when "dynamic" gets involved.</p> <p>Long-time readers know that <a href="https://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/">method type inference is one of my favourite parts of the C# language</a>; for new readers who might not be familiar with the feature, let me briefly describe it. The idea is that when you have a method, say, <span class="code">Select&lt;A, R&gt;(IEnumerable&lt;A&gt; items, Func&lt;A, R&gt; projection)</span>, and a call to the method, say <span class="code">Select(customers, c=&gt;c.Name)</span>, then we infer that you meant to say <span class="code">Select&lt;<font style="background-color: #ffff00">Customer, string</font>&gt;(customers, c=&gt;c.Name)</span>, rather than making you spell it out. In that case, we would first infer that the list of customers is an <span class="code">IEnumerable&lt;Customer&gt;</span> and therefore the type argument corresponding to A is Customer. From that we would infer that lambda parameter c is of type Customer, and therefore the result of the lambda is string, and therefore type argument corresponding to R is string. This algorithm is already complicated, but when dynamic gets involved, it gets downright weird.</p> <p>The problem that the language designers faced when deciding how method type inference works with dynamic is exacerbated by <a href="https://blogs.msdn.com/b/ericlippert/archive/2012/10/22/a-method-group-of-one.aspx">our basic design goal for dynamic, that I mentioned two weeks ago</a>: the runtime analysis of a dynamic expression honours all the information that we deduced at compile time. We only use the deduced-at-runtime types for the parts of the expression that were actually dynamic; the parts that were statically typed at compile time remain statically typed at runtime, not dynamically typed. Above we inferred R after we knew A, but what if "customers" had been of type dynamic? We now have a problem: depending on the runtime type of customers, type inference might succeed dynamically even though it seems like it must fail statically. But if type inference fails statically then the method is not a candidate, and, as we discussed two weeks ago, if the candidate set of a dynamically-dispatched method group is empty then overload resolution fails at compile-time, not at runtime. So it seems that type inference must succeed statically!</p> <p>What a mess. How do we get out of this predicament? The spec is surprisingly short on details; it says only:</p> <blockquote> <p class="spec">Any type argument that does not depend directly or indirectly on an argument of type dynamic is inferred using [the usual static analysis rules]. The remaining type arguments are <em>unknown. </em>[...] Applicability is checked according to [the usual static analysis rules] ignoring parameters whose types are <em>unknown. </em>(*)</p></blockquote> <p>So what we have here is essentially another type that spreads via a contagion model, the "unknown" type. Just as "possibly infected" is the transitive closure of the exposure relation in simplistic epidemiology, "unknown" is the transitive closure of the "depends on" relation in method type inference. </p> <p>For example, if we have:</p> <p class="code">void M&lt;T, U&gt;(T t, L&lt;U&gt; items)</p> <p>with a call </p> <p class="code">M(123, dyn);</p> <p>Then type inference infers that T is int from the first argument. Because the second argument is of dynamic type, and the formal parameter type involves type parameter U, we "taint" U with the "unknown type". </p> <p>When a tainted type parameter is "fixed" to its final type argument, we ignore all other bounds that we have computed so far, even if some of the bounds are contradictory, and infer it to be "unknown". So in this case, type inference would succeed and we would add M&lt;int, unknown&gt; to the candidate set. As noted above, we skip applicability checking for arguments that correspond to parameters whose types are in any way tainted.</p> <p>But where does the transitive closure of the dependency relationship come into it? In the C# 4 and 5 compilers we did not handle this particularly well, but in Roslyn we now actually cause the taint to spread. Suppose we have:</p> <p class="code">void M&lt;T, U, V&gt;(T t, L&lt;U&gt; items, Func&lt;T, U, V&gt; func)</p> <p>and a call</p> <p class="code">M(123, dyn, (t, u)=&gt;u.Whatever(t));</p> <p>We infer T to be int and U to be unknown. We then say that V depends on T and U, and so infer V to be unknown as well. Therefore type inference succeeds with an inference of <span class="code">M&lt;int, unknown, unknown&gt;</span>. </p> <p>The alert reader will at this point be protesting that no matter what happens with method type inference, this is going to turn into a dynamic call, and that lambdas are not legal in dynamic calls in the first place. However, we want to get as much high-quality analysis done as possible so that IntelliSense and other code analysis works correctly even in badly broken code. It is better to allow U to infect V with the unknown taint and have type inference succeed, as the specification indicates, than to bail out early and have type inference fail. And besides, if by some miracle we do in the future allow lambdas to be in dynamic calls, we'll already have a sensible implementation of method type inference.</p> <p><strong>Next time</strong> on Fabulous Adventures in Coding: <strong>Fabulous Adventures</strong>!</p> <hr>  <p>(*) That last clause is a bit unclear in two ways. First, it really should say "whose types are <em>in any way</em> unknown". L&lt;unknown&gt; is considered to be an unknown type. Second, along with skipping applicability checking we also skip constraint satisfaction checking. That is, we assume that the runtime construction of L&lt;unknown&gt; will provide a type argument that satisfies all the necessary generic type constraints. </p></div>]]></content:encoded>
    </item>
    <item>
      <title>Dynamic contagion, part one</title>
      <link>https://docs.microsoft.com/archive/blogs/ericlippert/dynamic-contagion-part-one</link>
      <pubDate>Mon, 05 Nov 2012 06:47:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Lippert]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericlippert/2012/11/05/dynamic-contagion-part-one/</guid>
      <description><![CDATA[Suppose you're an epidemiologist modeling the potential spread of a highly infectious disease. The...]]></description>
      <content:encoded><![CDATA[<div class="mine"> <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/29/89/metablogapi/5661.biohazard_2.gif" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-29-89-metablogapi/5661.biohazard_5F00_2.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="biohazard" border="0" alt="biohazard" align="left" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/29/89/metablogapi/5684.biohazard_thumb.gif" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-29-89-metablogapi/5684.biohazard_5F00_thumb.gif" width="240" height="231"></a>Suppose you're an epidemiologist modeling the potential spread of a highly infectious disease. The straightforward way to model such a series of unfortunate events is to assume that the population can be divided into three sets: the definitely infected, the definitely healthy, and the possibly infected. If a member of the healthy population encounters a member of the definitely infected or possibly infected population, then they become a member of the possibly infected population. (Or, put another way, the possibly infected population is closed transitively over the exposure relation.) A member of the possibly infected population becomes classified as either definitely healthy or definitely infected when they undergo some sort of test. And an infected person can become a healthy person by being cured. </p> <p>This sort of contagion model is fairly common in the design of computer systems. For example, suppose you have a web site that takes in strings from users, stores them in a database, and serves them up to other users. Like, say, this blog, which takes in comments from you, stores them in a database, and then serves them right back up to other users. That's a <a href="https://en.wikipedia.org/wiki/Cross-site_scripting">Cross Site Scripting</a> (XSS) attack waiting to happen right there. A common way to mitigate the XSS problem is to use <a href="https://en.wikipedia.org/wiki/Taint_checking">data tainting</a>, which uses the contagion model to identify strings that are possibly hostile. Whenever you do anything to a potentially-hostile string, like, say, concatenate it with a non-hostile string, the result is a possibly-hostile string. If the string is determined via some test to be benign, or can have its potentially hostile parts stripped out, then it becomes safe. </p> <p>The "dynamic" feature in C# 4 and above has a lot in common with these sorts of contagion models. As I pointed out last time, when an argument of a call is dynamic then odds are pretty good that the compiler will classify the result of the call as dynamic as well; the taint spreads. In fact, when you use almost any operator on a dynamic expression, the result is of dynamic type, with a few exceptions. ("is" for example always returns a bool.)&nbsp; You can "cure" an expression to prevent it spreading dynamicism by casting it to object, or to whatever other non-dynamic type you'd like; casting dynamic to object is an identity conversion. </p> <p>The way that dynamic is contagious is an emergent phenomenon of the rules for working out the types of expressions in C#. There is, however, one place where we explicitly use a contagion model inside the compiler in order to correctly work out the type of an expression that involves dynamic types: it is one of the most arcane aspects of method type inference. Next time I'll give you all the rundown on that.</p></div>]]></content:encoded>
    </item>
    <item>
      <title>A method group of one</title>
      <link>https://docs.microsoft.com/archive/blogs/ericlippert/a-method-group-of-one</link>
      <pubDate>Mon, 22 Oct 2012 06:24:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Lippert]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericlippert/2012/10/22/a-method-group-of-one/</guid>
      <description><![CDATA[I'm implementing the semantic analysis of dynamic expressions in Roslyn this week, so I'm fielding...]]></description>
      <content:encoded><![CDATA[<div class="mine"> <p>I'm implementing the semantic analysis of dynamic expressions in Roslyn this week, so I'm fielding a lot of questions within the team on the design of the dynamic feature of C# 4. A question I get fairly frequently in this space is as follows:</p> <p class="code">public class Alpha<br>{<br>&nbsp; public int Foo(string x) { ... }<br>}<br>...<br>dynamic d = whatever;<br>Alpha alpha = MakeAlpha();<br>var result = alpha.Foo(d);</p> <p>How is this analyzed? More specifically, what's the type of local result?</p> <p>If the receiver (that is, alpha) of the call were of type dynamic then there would be little we could do at compile time. We'd analyze the compile-time types of the arguments and emit a dynamic call site that caused the semantic analysis to be performed at runtime, using the runtime type of the dynamic expression. But that's not the case here. We know at compile time what the type of the receiver is. One of the design principles of the C# dynamic feature is that if we have a type that is known at compile time, then at runtime the type analysis honours that. In other words, we only use the runtime type of the things that were actually dynamic; everything else we use the compile-time type. If MakeAlpha() returns a derived class of Alpha, and that derived class has more overloads of Foo, we don't care.</p> <p>Because we know that we're going to be doing overload resolution on a method called Foo on an instance of type Alpha, we can do a "sanity check" at compile time to determine if we know that for sure, this is going to fail at runtime. So we do overload resolution, but instead of doing the full overload resolution algorithm (eliminate inapplicable candidates, determine the unique best applicable candidate, perform final validation of that candidate), we do a partial overload resolution algorithm. We get as far as eliminating the inapplicable candidates, and if that leaves one or more candidates then the call is bound dynamically. If it leaves zero candidates then we report an error at compile time, because we know that nothing is going to work at runtime.</p> <p>Now, a seemingly reasonable question to ask at this point is: overload resolution in this case could determine that there is exactly one applicable candidate in the method group, and therefore we can determine statically that the type of result is int, so why do we instead say that the type of result is dynamic?</p> <p>That appears to be a reasonable question, but think about it a bit more. If you and I and the compiler know that overload resolution is going to choose a particular method then <em>why are we making a dynamic call in the first place?</em> Why haven't we cast d to string? This situation is rare, unlikely, and has an easy workaround by inserting casts appropriately (either casting the call expression to int or the argument to string). Situations that are rare, unlikely and easily worked around are poor candidates for compiler optimizations. You asked for a dynamic call, so you're going to get a dynamic call.</p> <p>That's reason enough to not do the proposed feature, but let's think about it a bit more deeply by exploring a variation on this scenario that I glossed over above. Eta Corporation produces:</p> <p class="code">public class Eta {}</p> <p>and Zeta Corporation extends this code:</p> <p class="code">public class Zeta : Eta<br>{<br>&nbsp; public int Foo(string x){ ... }<br>}<br>...<br>dynamic d = whatever;<br>Zeta zeta = new Zeta();<br>var result = zeta.Foo(d);</p> <p>Suppose we say that the type of result is int because the method group has only one member. Now suppose that in the next version, Eta Corporation supplies a new method:</p> <p class="code">public class Eta <br>{<br>&nbsp; public string Foo(double x){...}<br>}</p> <p>Zeta corporation recompiles their code, and hey presto, suddenly result is of type dynamic! Why should Eta Corporation's change <strong>to the base class</strong> cause the semantic analysis of code that uses a <strong>derived</strong> class to change? This seems unexpected. C# has been carefully designed to avoid these sorts of "Brittle Base Class" failures; <a href="https://blogs.msdn.com/b/ericlippert/archive/tags/brittle+base+classes/">see my other articles on that subject for examples of how we do that.</a></p> <p>We can make a bad situation even worse. Suppose Eta's change is instead:</p> <p class="code">public class Eta <br>{<br>&nbsp; protected string Foo(double x){...}<br>}</p> <p>Now what happens? Should we say that the type of result is int when the code appears outside of class Zeta, because overload resolution produces a single applicable candidate, but dynamic when it appears inside, because overload resolution produces two such candidates? That would be quite bizarre indeed.</p> <p>The proposal is simply too much cleverness in pursuit of too little value. We've been asked to perform a dynamic binding, and so we're going to perform a dynamic binding; the result should in turn be dynamic. The benefits of being able to statically deduce types of dynamic expressions does not pay for the costs, so we don't attempt to do so. <strong>If you want static analysis then don't turn it off in the first place.</strong></p> <p><strong>Next time:</strong> the dynamic taint of method type inference.</p></div>]]></content:encoded>
    </item>
    <item>
      <title>Is C# a strongly typed or a weakly typed language?</title>
      <link>https://docs.microsoft.com/archive/blogs/ericlippert/is-c-a-strongly-typed-or-a-weakly-typed-language</link>
      <pubDate>Mon, 15 Oct 2012 09:26:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Lippert]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericlippert/2012/10/15/is-c-a-strongly-typed-or-a-weakly-typed-language/</guid>
      <description><![CDATA[Presented as a dialogue, as is my wont!  Is C# a strongly typed or a weakly typed language?  Yes....]]></description>
      <content:encoded><![CDATA[<div class="mine">  <p>Presented as a dialogue, as is my wont!</p>  <p><strong>Is C# a strongly typed or a weakly typed language?</strong></p>  <p>Yes.</p>  <p><strong>That is unhelpful.</strong></p>  <p>I don't doubt it. Interestingly, if you rephrased the question as an "and" question, the answer would be the same.</p>  <p><strong>What? You mean, is C# a strongly typed <em>and</em> a weakly typed language? </strong></p>  <p>Yes, C# is a strongly typed language and a weakly typed language.</p>  <p><strong>I'm confused.</strong></p>  <p>Me too. Perhaps you should tell me precisely what you mean by "strongly typed" and "weakly typed".</p>  <p><strong>Um. I don't actually know what I mean by those terms, so perhaps that is the question I should be asking. What does it <em>really</em> mean for a language to be "weakly typed" or "strongly typed"?</strong></p>  <p>"Weakly typed" means "<em>this language uses a type verification system that I find distasteful</em>", and "strongly typed" means "<em>this language uses a type system that I find attractive</em>".</p>  <p><strong>No way!</strong></p>  <p>Way, dude.</p>  <p><strong>Really?</strong></p>  <p>These terms are meaningless and you should avoid them. <a href="https://en.wikipedia.org/wiki/Strong_typing">Wikipedia</a> lists <em><a href="https://www.youtube.com/watch?v=ll7rWiY5obI">eleven</a></em> different meanings for "strongly typed", several of which contradict each other. Any time two people use "strongly typed" or "weakly typed" in a conversation about programming languages, odds are good that they have two subtly or grossly different meanings in their heads for those terms, and are therefore automatically talking past each other.</p>  <p><strong>But surely they mean <em>something</em> other than "unattractive" or "attractive"!</strong></p>  <p>I do exaggerate somewhat for comedic effect. So lets say: a more-strongly-typed language is one that has some <em>restriction</em> in its type system that a more-weakly-typed language it is being compared to lacks. That's all you can really say without more context.</p>  <p><strong>How can I have sensible conversations about languages and their type systems then?</strong></p>  <p>You can provide the missing context. Instead of using "strongly typed" and "weakly typed", actually describe the restriction you mean. For example, C# is <em>for the most part</em> a <strong>statically typed</strong> language, because the compiler determines facts about the types of every expression. C# is <em>for the most part</em> a <strong>type safe</strong> language because it prevents values of one static type from being stored in variables of an incompatible type (and other similar type errors). And C# is <em>for the most part </em>a <strong>memory safe</strong> language because it prevents accidental access to bad memory.</p>  <p>Thus, someone who thinks that "strongly typed" means "the language <em>encourages</em> static typing, type safety and memory safety <em>in the vast majority of normal programs</em>" would classify C# as a "strongly typed" language. C# is certainly more strongly typed than languages that do not have these restrictions in their type systems.</p>  <p>But here's the thing: because C# is a pragmatic language there is a way to override all three of those safety systems. Cast operators and "dynamic" in C# 4&nbsp;override compile-time type checking and replace it with runtime type checking, and "unsafe" blocks allow you to turn off type safety and memory safety should you need to. Someone who thinks that "strongly typed" means "the language <em>absolutely positively guarantees </em>static typing, type safety and memory safety <em>under all circumstances</em>" would quite rightly classify C# as "weakly typed". C# is not as strongly typed as languages that do enforce these restrictions all the time.</p>  <p>So which is it, strong or weak? It is impossible to say because it depends on the point of view of the speaker, it depends on what they are comparing it to, and it depends on their attitude towards various language features. It's therefore best to simply avoid these terms altogether, and speak more precisely about type system features.</p>  </div>]]></content:encoded>
    </item>
    <item>
      <title>High Altitude</title>
      <link>https://docs.microsoft.com/archive/blogs/ericlippert/high-altitude</link>
      <pubDate>Fri, 12 Oct 2012 07:38:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Lippert]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericlippert/2012/10/12/high-altitude/</guid>
      <description><![CDATA[No computer programming stuff today; just some fun for Friday. As I'm writing this Felix...]]></description>
      <content:encoded><![CDATA[<div class="mine"> <p>No computer programming stuff today; just some fun for Friday.</p> <p>As I'm writing this <a href="https://www.pbs.org/newshour/rundown/2012/10/felix-baumgartner-poised-to-attempt-worlds-highest-skydive.html">Felix Baumgartner's attempt to set the world record for skydiving height by diving from a helium balloon has been scrubbed due to bad weather</a>. This attempt has got me thinking of my good friend JB, who back in 1982 <a href="https://en.wikipedia.org/wiki/Hang_gliding#Records">set the world record</a> (*) for hang gliding height by similarly using a helium balloon. </p> <p>JB is one of those people who proves the truth of the saying that you really can do anything you put your mind to, as he's been a world-record breaking hang glider pilot, skydiver, balloonist, airplane pilot, ultra-marathon runner, shuttle astronaut candidate (**), upper-atmosphere physicist, microgravity physicist, nuclear physicist, father, and I'm probably missing a dozen more accomplishments in there. And teacher! When I was a child he taught me useful skills like how to estimate large numbers, how to do trigonometry, and how to do calculus, usually by pointing out things on the beach and then doing math in the sand, like Archimedes. How many grains of sand are on this beach? How far away is the horizon when you stand on the roof of the cottage? What shape path does this rock make in the air when you throw it? These sorts of questions fascinated me as a child, and, I suppose, still do.</p> <p>Anyway, I recently learned that JB has uploaded the short film his brother Bims made to document the successful attempt at the record. Check it out, and enjoy the hairstyles of the 1980s: <a href="https://www.youtube.com/watch?v=g9rU2yNzGOE"><strong>Project Hang Glide</strong></a></p> <hr>  <p>(*) It's in the 1988 Guinness Book of World Records. </p> <p>(**) His microgravity experiment ended up flying on the <a href="https://en.wikipedia.org/wiki/Vomit_comet">Vomit Comet</a> rather than the shuttle. </p></div>]]></content:encoded>
    </item>
    <item>
      <title>Does Not Compute</title>
      <link>https://docs.microsoft.com/archive/blogs/ericlippert/does-not-compute</link>
      <pubDate>Wed, 10 Oct 2012 06:27:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Lippert]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericlippert/2012/10/10/does-not-compute/</guid>
      <description><![CDATA[One of the most basic ways to think about a computer program is that it is a device which takes in...]]></description>
      <content:encoded><![CDATA[<div class="mine"> <p>One of the most basic ways to think about a computer program is that it is a device which takes in integers as inputs and spits out integers as outputs. The C# compiler, for example, takes in source code strings, and those source code strings are essentially nothing more than enormous binary numbers. The output of the compiler is either diagnostic text, or strings of IL and metadata, which are also just enormous binary numbers.&nbsp; Because the compiler is not perfect, in some rare cases it terminates abnormally with an internal error message. But those fatal error messages are also just big binary numbers. So let's take this as our basic model of a computer program: a computer program is a device that either (1) runs forever without producing output, or (2) computes a function that maps one integer to another.</p> <p>So here's an interesting question: are there functions which cannot be computed, even in principle on a machine with arbitrarily much storage, by <em>any</em> C# program (*)? </p> <p>We already know the answer to that question. <a href="https://blogs.msdn.com/b/ericlippert/archive/2011/02/24/never-say-never-part-two.aspx">Last year I pointed out that the Halting Problem is not solvable by any computer program</a>, because the assumption that it is solvable leads to a logical contradiction. But the Halting Problem is just a function on integers. Let's say that the input of our function H is a number which when written out in binary is a Unicode string that might contain a C# program. The output is 1 if the program is an illegal C# program, 2 if it is a legal C# program which halts, and 3 if it is a legal C# program which does not halt. If it were possible to write a program that reliably computes function H and always terminates then it would be possible to use it to solve the Halting Problem, which we've shown is impossible. Therefore H is not a computable function.</p> <p>Let's explore this a bit further. The "Turing Machine" model of computing is that a computer is a machine that has three kinds of storage: first, there's a fixed amount of "internal" storage that describes the current state of the processor, second, there is arbitrarily much "external" storage in the form of paper tape, disk drives, or whatever, that can contain binary data, and third, there is some way of identifying the "current position" being manipulated in the external storage. The Turing Machine also has strict rules that describe how to change the internal state, the external state, and the current position. One of the internal states is the "start" state, and one of the internal states is the "halt" state; once the machine gets to the halting state, it stops. Otherwise, it runs forever.</p> <p>Without loss of generality, let's suppose that our Turing Machine's external storage is arbitrarily many bits, either zero or one, and that the internal storage is some fixed number of bits, say n. This is pretty restrictive, but we haven't actually lost anything fundamental here. Real computers of course give the appearance of manipulating storage that consists of 32 bit integers or 64 bit doubles or whatever, but at some level inside the processor, it is manipulating individual bits. There is no difference in principle between a machine that manipulates one bit at a time and a machine that manipulates 64 bits at a time; the latter is simply more convenient. </p> <p>So then how many rules do we need to come up with for our Turing machine? A Turing machine with n bits of internal state has 2<sup>n</sup> possible states, and there are two possibilities for the value at the "current position" in the external state. (**) So that means that there are 2<sup>n+1</sup> state transition rules. Each transition rule will have to encode three things: (1) what are the n bits of the new internal state? (2) what value should the external state be changed to? and (3) how should we update the current position?</p> <p>Again without loss of generality, we can update the current position by decreasing it by one, increasing it by one, or leaving it the same. In practice that is inconvenient, but in principle that is enough. So those are three possibilities. Thus, each state transition rule is one of 2 x 2<sup>n</sup> x 3 possibilities. There are 2<sup>n+1</sup> state transition rules. Therefore the total number of possible Turing Machines that have n bits of internal storage is 3 x 2<sup>n+1 </sup> raised to the 2<sup>n+1 </sup>power, which, yes, grows pretty quickly as n gets large, but which is clearly a finite number. </p> <p>Each one of these n-bit Turing Machines essentially computes a function. You start it up with the external storage in a particular state and the machine either runs forever, or after some finite number of steps it halts. If it halts, then the output of the function is the value left behind in the external storage.</p> <p>Again without loss of generality, let's consider the value computed by each one of those possible Turning machines when the external storage is initially all zeros. When given that starting configuration, each of those Turing machines either runs for some number of steps and then halts with the result, or it runs forever. Let's ignore the ones that run forever. Of the ones that are left, the ones that terminate, one of them must run the longest (***). That is, one of those machines that halts must have the largest number of steps taken before entering the halting state. </p> <p>We therefore can come up with a function S that goes from integers to integers. The function S takes in n, the number of bits in the Turing Machine internal state, and gives you back the largest number of steps any of the possible n-bit Turing Machines that halts takes to halt. That is, S takes in the number of bits of internal storage and gives you back the amount of time you have to wait for the <strong>slowest</strong> of the n-bit machines that actually terminates, when it is started with empty external storage.</p> <p><strong>Is S a computable function? </strong>Can we write a computer program that computes it?</p> <p>Your intuition should be telling you "no", but do you see why?</p> <p>.</p> <p>.</p> <p>.</p> <p>.</p> <p>.</p> <p>.</p> <p>.</p> <p>.</p> <p><a href="https://www.youtube.com/watch?v=ieuBkWHfCuc">Because if S were computable then H would be computable too!</a> All we'd have to do to compute H is to make a computer program that compiles a given C# program into a Turing Machine simulator that starts with an empty tape. We take the number of bits of state, n, of that Turing Machine, and compute S(n). Then we run the Turing Machine simulator and <em>if it takes more than S(n) steps then we know that it must have been one of the n-bit Turing machines that runs forever</em>. We'd then be able to reliably compute H in finite time. Since we already know that H is not reliably computable in finite time then we know that S must not be computable either.</p> <p>The argument that I'm advancing here is known as the "Busy Beaver" argument because the n-bit Turing Machine that runs the longest is the "busiest beaver". I've tweaked the way that it is usually presented; rather than the <strong>n-bit</strong> Turing Machine that <strong>runs the longest</strong> before terminating, the "busiest beaver" is traditionally defined as the <strong>k-state</strong> Turing Machine that <strong>produces the largest output</strong>. The two characterizations are essentially equivalent though; neither version of the function is computable. </p> <p>An interesting fact about the busy beaver function (either way you characterize it) is that the function grows <em>enormously fast</em>. It's easy to think of functions that grow quickly; even simple functions like n! or 2<sup>n</sup> grow to astronomical levels for relatively small values of n, like 100. But our busiest beaver function S(n) grows faster than <em>any</em> computable function. That is, think of a function that grows quickly where you could write a program to compute its value in finite time; the busiest beaver function grows <em>faster</em> than your function, no matter how clever you are in coming up with a fast-growing function. Do you see why? You've got all the information you need here to work it out. (****)</p> <hr>  <p>(*) Of course, there is nothing special about C#; it is a general-purpose programming language. We'll take as given that if there is a function that cannot be computed in C# then that function cannot be computed by any program in any programming language.</p> <p>(**) Of course, we don't need to state transitions from the halting state, but, whatever. We'll ignore that unimportant detail.</p> <p>(***) Of course, there could be a tie for longest, but that doesn't matter.</p> <p>(****) Of course, even if the busiest beaver function did not grow absurdly quickly, the fact that it clearly grows more than exponentially is evidence that our proposed technique for solving the Halting Problem would be impractical were it not impossible. Compiling a non-trivial C# program to a Turing Machine simulator would undoubtedly produce a machine with more than, say, 100 bits of state. There are an enormous number of possible Turing Machines with 100 bits of internal state, and the one that runs the longest before it halts undoubtedly runs longer than the universe will last.</p></div>]]></content:encoded>
    </item>
    <item>
      <title>How do we ensure that method type inference terminates?</title>
      <link>https://docs.microsoft.com/archive/blogs/ericlippert/how-do-we-ensure-that-method-type-inference-terminates</link>
      <pubDate>Tue, 02 Oct 2012 09:48:31 GMT</pubDate>
      <dc:creator><![CDATA[Eric Lippert]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericlippert/2012/10/02/how-do-we-ensure-that-method-type-inference-terminates/</guid>
      <description><![CDATA[I missed the party. I was all set to be on that massive wave of announcements about TypeScript, and...]]></description>
      <content:encoded><![CDATA[<div class="mine"> <p>I missed the party. I was all set to be on that <a href="https://blogs.msdn.com/b/somasegar/archive/2012/10/01/typescript-javascript-development-at-application-scale.aspx">massive</a> wave of <a href="https://channel9.msdn.com/posts/Anders-Hejlsberg-Introducing-TypeScript">announcements</a> about <a href="https://www.typescriptlang.org/">TypeScript</a>, and then a family emergency kept me away from computers from Thursday of last week until just now, and I did not get my article in the queue. Suffice to say that I am <strong>SUPER EXCITED</strong> about TypeScript. Long-time readers of this blog know that I <a href="https://blogs.msdn.com/b/ericlippert/archive/tags/jscript/">have a long history with ECMAScript</a>, and I've wanted features like this for quite some time. Since I've missed the first wave I'm going to digest some of the initial reactions and hopefully post something a bit more thoughtful farther down the road.</p> <p>Therefore, rather than talking about TypeScript today, here's a question I got from a coworker recently: since it is obviously important that the C# compiler not go into infinite loops, <strong>how do we ensure that the method type inference algorithm terminates?</strong></p> <p>The answer is quite straightforward actually, but if you are not familiar with method type inference then this article is going to make no sense. Check out my <a href="https://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/">type inference archive</a>, and specifically <a href="https://blogs.msdn.com/b/ericlippert/archive/2006/11/17/a-face-made-for-email-part-three.aspx">this video</a>, if you need a refresher.</p> <p>Method type inference since C# 3.0 basically works like this: we create a set of <strong>bounds</strong> on each method type parameter. We then "fix" each type parameter to a member of its bounds set. Once every type parameter is fixed, method type inference has succeeded. If any type parameter cannot be fixed for some reason then type inference fails. We ensure that type inference terminates by going into a loop. If we manage to make it through the body of the loop without fixing at least one type parameter then type inference fails. Therefore, the type inference loop can run at most n times if the method has n type parameters. </p> <p>That's a bit highfalutin; let me flesh that out a bit. A "bound" is nothing more than a type, and a bound can be "upper", "lower" or "exact". For example, suppose we have a type parameter T with three bounds: a lower bound of Giraffe, an exact bound of Mammal, and an upper bound of Animal. Let's say that Animal is a "<a href="https://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx">larger</a>" type than Mammal (because all Mammals are Animals but not all Animals are Mammals, thus Animal must be the larger type), and Giraffe is a "smaller" type than Mammal. Given this set of bounds we know that T must be inferred to be first, either Giraffe or a type larger than Giraffe, because Giraffe is a lower bound; you can't infer a type smaller than Giraffe. Second, we know that T must be Mammal, exactly. And third, we know that T must be either Animal or a type smaller than Animal, because Animal is an upper bound. We cannot infer a type larger than Animal. The C# compiler deduces that Mammal is the only type in the set that meets all three requirements, and so T would be fixed to Mammal. If there are multiple types in the set that meet all the requirements (which of course cannot happen if there are any exact bounds!) then we pick the largest such type. (*)</p> <p>The interesting part of method type inference is how we deal with lambdas. Suppose we have a method <span class="code">Select&lt;A, R&gt;(I&lt;A&gt;, Func&lt;A, R&gt;)</span> where the second argument is <span class="code">c=&gt;c.Name</span>. We say that A is an "input" type parameter and R is an "output" type parameter. (It is of course possible for a type parameter to be both an input and output type parameter!) Furthermore, we say that R "depends on" A, because the type of A could possibly determine the type of R. (Of course the "depends" relationship can be cyclic.)</p> <p>The type inference algorithm, at a high level, goes like this:</p> <ul> <li>Add bounds to type parameters based on all non-lambda arguments, and all lambda arguments where the delegate type has no type parameters in its inputs.  </li><li>Loop  <ul> <li>Is every type parameter fixed?  <ul> <li>Type inference has succeeded. Terminate the algorithm.</li></ul> </li><li>Is there any lambda argument converted to a delegate type where the inputs of the delegate type are all known and the output type involves an unfixed type parameter?  <ul> <li>Deduce the return type of all such lambdas and make inferences that add bounds to the corresponding delegate's output types.</li></ul> </li><li>Is there any unfixed, bounded type parameter that does not appear in an output type of a delegate that has unfixed input types?  <ul> <li>Fix all such type parameters and go back to the top of the loop.</li></ul> </li><li>Is there any unfixed, bounded type parameter such that an unfixed type parameter depends on it, directly or indirectly?  <ul> <li>Fix all such type parameters and go back to the top of the loop.</li></ul> </li><li>If we make it here then we failed to make progress; we have just as many fixed type parameters as we started with. Type inference fails. Terminate the algorithm.</li></ul></li></ul> <p>So, for example, if we had <span class="code">Select(customers, c=&gt;c.Name);</span> where customers implements I&lt;Customer&gt; then we start by inferring that A has a lower bound of Customer (**). We have no lambda arguments that correspond to formal parameters where the delegate type has no type parameters in its inputs, so we enter the loop. </p> <p>Is every type parameter fixed? No. </p> <p>Is there any lambda argument converted to a delegate type where the inputs are known and the output involves an unfixed type parameter?</p> <p>No. There is a lambda argument converted to a delegate type, and the output involves unfixed type parameter R, but the input type is A and A is not fixed. So we have no inferences to make.</p> <p>Is there an unfixed type parameter that has bounds and does not appear in an output type of a delegate that has unfixed input types?</p> <p>Yes. A has bounds and does not appear as an output type, period.</p> <p>Therefore we fix A. It has only one bound, Customer, so we fix it to Customer. We have made progress, so we go back to the top of the loop.</p> <p>Is every type parameter fixed? No.</p> <p>Is there any lambda argument converted to a delegate type where the inputs are known and the output involves an unfixed type parameter? Yes!</p> <p>So now we make an inference. A is fixed to Customer, so we add the type of Customer.Name, say, string, as a lower bound to R.</p> <p>Now we must fix something. Is there an unfixed type parameter that has bounds and does not appear in an output type of a delegate that has unfixed input types?</p> <p>Yes. R is unfixed, it has bounds, and it appears as an output type of a delegate that has fixed input types, so it is a candidate for fixing. We fix R to its only bound, string, and start the loop again.</p> <p>Is every type parameter fixed? Yes. So we're done.</p> <p>This technique of preventing infinite loops by requiring that each loop iteration make progress is quite useful, and clearly in this case it guarantees that the algorithm executes the loop no more times than there are type parameters to fix. </p> <p>You might wonder if it is therefore the case that method type inference is O(n) in the number of type parameters. It turns out that it is not, for several reasons. First, as a practical matter it only makes sense to determine the asymptotic order of an algorithm if the size of the problem is likely to become large. I've never seen a method with more than five type parameters in the wild, and even that is pretty unusual. Most generic methods have one or two type parameters. Second, doing the analysis of the lambdas is the expensive part, and it only really makes sense to analyze the behaviour of the most expensive part. We <a href="https://blogs.msdn.com/b/ericlippert/archive/2007/03/28/lambda-expressions-vs-anonymous-methods-part-five.aspx">already know that analyzing lambdas is, worst case, an NP-HARD problem</a> so whether or not method type inference is O(some polynomial) is possibly not that relevant. Third, you'll notice that in my sketch of the algorithm we have to answer questions like "is there any unfixed type parameter that has an unfixed type parameter that depends on it?" This requires solving a graph-traversal problem, whose asymptotic cost we have not analyzed! I won't take you through the boring analysis, but suffice to say there could be O(n<sup>2</sup>) dependency relationships that each cost O(n) to analyze, and we could go through the loop n times, for an extremely unlikely worst case of O(n<sup>4</sup>). The implementation of this algorithm is actually O(n<sup>2</sup>) in the common case; because n is likely to be small, as I said, we have not put the effort into more sophisticated algorithms that can solve these graph problems even faster in the asymptotic case.</p> <hr>  <p>(*) Note that this algorithm is consistent with other type inference features in C# in two ways. First, when asked to infer a best type from a set of types, we always choose a type from the set. We never say "well we have Dog and Cat in the set so let's infer Mammal". Second, when faced with multiple possible "best" types, we pick the largest. There is an argument to be made for picking the smallest, but picking the largest seems to match more people's intuitions of what the right choice is.</p> <p>(**) Assuming that the type I&lt;T&gt; is covariant in T. If it were contravariant then we would deduce an upper bound, and if it were invariant then we would deduce an exact bound. <a href="https://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/">See my series on variance if that is not clear.</a> </p></div>]]></content:encoded>
    </item>
  </channel>
</rss>