Eric Lippert

blogs.msdn.microsoft.com/ericlippert · Personal blog · on HN since 2015

Eric Lippert, a former C# compiler team member at Microsoft, wrote about C# language design, semantics, and compiler behavior.

What HN saysHN commenters recommend his series on covariance and contravariance and his posts on continuation-passing style and async. They also cite him for explaining C# behavior.
37HN people shared it
28linked it in comments
10stories submitted
50story points
7 years agolast shared
2015people per year2026

Most-shared posts

  1. 1
  2. 2
  3. 3
    How Many Passes? (2010)
    2 people · 21 points · first shared 2015 · 2 comments on HN
  4. 4
    The Truth About Value Types (2010)
    2 people · 13 points · first shared 2016 · 1 comments on HN
  5. 5
    Why Are So Many of the Framework Classes Sealed? (2004)
    2 people · 5 points · first shared 2018 · 3 comments on HN
  6. 6
    What would Feynman do? (2011)
    2 people · 1 points · first shared 2016 · discussion on HN
  7. 7
    Vexing Exceptions
    2 people · 1 points · first shared 2016 · discussion on HN
  8. 8
    Whats the difference remainder vs modulus
    2 people · first shared 2017
  9. 9
    Curiouser and curiouser: recursive generic types in C#
    1 people · 2 points · first shared 2017 · discussion on HN
  10. 10
  11. 11
    Five-Dollar Words for Programmers (2005-2009)
    1 people · 2 points · first shared 2018 · discussion on HN
  12. 12
    What is this thing you call a “type”
    1 people · 2 points · first shared 2017 · discussion on HN
  13. 13
    Microsoft Team Zero Bug Bounce (2004)
    1 people · 1 points · first shared 2016 · discussion on HN
  14. 14
    Covariance and contravariance
    1 people · first shared 2017
  15. 15
    Why have a stack
    1 people · first shared 2016

What HN people wrote when they linked it

chrisoverzero · 2018-05-10
> No one seems to know why C# behaves the way it does. Operators are lifted[0] over nullability in C#. Every value type T can be converted implicitly to Nullable<T>. When `10 * null` is typechecked, both sides of * are typed as Nullable<T>. The * operator then acts like the pseudo-Haskell (*) <$> 10 <*> null or, I guess liftA2 (*) (Just 10) Nothing The semantics of Nullable<T> are similar to those of an optional type, with some implicit mapping and lifting. In that context, null acts less like null. (Thanks to convenient conversions.) Note that the following doesn't throw: int? value = null; value.HasValue // == false [0]: https://blogs.msdn.microsoft.com/ericlippert/2007/06/27/what-exactly-d…
pauldino · 2018-03-12
It's implicit based on the appropriate method overload being present. In fact that's the way foreach loops and LINQ already work in C#, you don't actually need to implement IEnumerable or IQueryable to use them. https://blogs.msdn.microsoft.com/ericlippert/2011/06/30/following-the-…
WorldMaker · 2017-06-27
I recall Eric Lippert's article series on the topic to be well written and well explained. It starts here: https://blogs.msdn.microsoft.com/ericlippert/2007/10/16/covariance-and… You can follow along further through the tag: https://blogs.msdn.microsoft.com/ericlippert/tag/covariance-and-contra…
Patient0 · 2017-01-12
Also worth reading to understand how Async/Await are implemented: https://blogs.msdn.microsoft.com/ericlippert/2010/10/21/continuation-p…
lacampbell · 2016-12-12
I would love to see the code used for some of these instructions. Their description of "swap" for the stack VM jumped out at me: > pop 1 st and 2nd value out of local stack and swap them You don't need to pop at all for swap. The stack isn't actually changing size and can be modified in place. You also should only have one pop for 'add', etc. A lot of people don't seem to realise this. Also, this article may be of interest: https://blogs.msdn.microsoft.com/ericlippert/2011/11/28/why-have-a-sta… TL;DR - a stack machine is conceptually simpler than a register machine, and it doesn't matter if it's slower since you are JIT'ing it anyway.
alasdair_ · 2016-10-07
It's not him but I still love this article about his thought process: https://blogs.msdn.microsoft.com/ericlippert/2011/02/14/what-would-fey…
adzm · 2016-06-01
Then you'd probably love to know why the OLE DATE epoch is 1899-12-30... also the B in BSTR is for Basic! https://blogs.msdn.microsoft.com/ericlippert/2003/09/16/erics-complete…
rusanu · 2016-08-25
Microsoft runs internally similar tools. The usual deal is that grandfathered issues (ie. issues found by new code analysis tools on old code base) are generally not fixed, and the warning is instead silenced (all tools have means to suppress specific warning for specific code place). This is done because the risk to fix a code analysis issue on old code base is often higher than the benefit. New code on the other hand is usually required to pass all static analysis without introducing new warnings, and is often enforced by automated code review (bots that runs static analysis will mark the code review and it will not be possible to check it in). From time to time some teams form to work on fixing static analysis code warnings on old code, but is not a high priority. Of course a public PR event like the OP may trigger some action, is going to be up to the individual team priorities, policy, schedule, workload etc. This may sound like laziness or carelessness, but these are good engineers with plenty of experience that are capable of judging risk vs. benefits. If the code was like this for years and no actual bug was reported, is not always worth modifying it. Eric Lippert has a nice blog about How many Microsoft employees does it take to change a lightbulb? [0] and why some of these 'trivial' changes for a small project add up to a risky change at MS scale. - [0]…
dragonwriter · 2019-09-19
> Python does have explicit destructors, at least when using CPython Python has finalizers rather than destructors, though they are sometimes referred to as destructors (the Python docs explicitly note that this is incorrect but not why, there is discussion of the difference—inbthe context of C#—here: https://blogs.msdn.microsoft.com/ericlippert/2010/01/21/whats-the-diff… )
Gibbon1 · 2019-07-12
I saw your comment and decided to look up how C#'s compiler does things. It does two passes of the program text. And then does three dozen passes after that. Each pass does what you suggest, only one thing. https://blogs.msdn.microsoft.com/ericlippert/2010/02/04/how-many-passe… I think it's still fast because the passes are all or mostly O(n).
neves · 2019-05-07
Nice. I also like this similar version from Microsoft: How many Microsoft employees does it take to change a lightbulb? https://blogs.msdn.microsoft.com/ericlippert/2003/10/28/how-many-micro…
pjmlp · 2019-02-14
Runtimes and languages go hand-in-hand, a runtime that doesn't support everything that one expects from the standard library breaks compatibility. Code starts getting full of #ifdefs Siverlight, .NET Core, WinRT, UWP just to give three reboots. No support for dynamic APIs, appdomains, IL generation on the fly, reflection APIs done in a different way, ... Actually C# is not fully backwards compatible, variables declared on foreach statements changed their semantics in C# 5. https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-t… MS-DOS is only supported in 32 bit variants, a species in extinsion.
ridiculous_fish · 2019-01-23
async is part of the method signature, the public facing part of the method. But it controls an implementation detail, namely whether the function body may use await (as you say asynchronous functions are not required to use await). I found a link [1] that described async as a compatibility affordance in C# 5: legacy code may use await as a variable name, so async opts into the contextual await keyword. But Dart doesn't have such legacy, so the keyword doesn't seem as well motivated. https://blogs.msdn.microsoft.com/ericlippert/2010/11/11/asynchrony-in-…
int_19h · 2018-12-20
VBScript is basically dynamically typed VB6. It's not a nice language - it has all the worst parts of VB6, and then adds its own. Take a look at some of Eric Lippert's old blog posts from the days when he was working on VBScript: https://blogs.msdn.microsoft.com/ericlippert/tag/vbscript/ To give one example, that is somewhat relevant here because it describes one of the biggest misfeatures of the language - default properties - that is used in the exploit: https://blogs.msdn.microsoft.com/ericlippert/2005/08/30/vbscript-defau…
MaxBarraclough · 2018-11-22
Was `Coordinate` a class or a struct? C# structs generally [0][1] don't force use of the garbage-collected heap. [0] https://blogs.msdn.microsoft.com/ericlippert/2010/09/30/the-truth-abou… (ignore the usual comments telling the reader they are wrong for wondering about whether the garbage-collected heap is used) [1] https://jacksondunstan.com/articles/3453
LandR · 2018-08-23
The site seems to be down, but confusion about the difference arises in C# too. C# does not have a mod operator, the % operator is a remainder operator. https://blogs.msdn.microsoft.com/ericlippert/2011/12/05/whats-the-diff…
matthewwarren · 2018-08-21
Just a small thing, the Roslyn compiler (or any C# compiler) does very few optimisations, see https://blogs.msdn.microsoft.com/ericlippert/2009/06/11/what-does-the-… for some details. Almost all of the 'compiler' optimisations are done by the JIT at run-time when it converts the IL code into machine/assembly code
jasode · 2018-04-29
Fyi... a related debate is "sealed classes" by default. E.g. Eric Lippert's comments: https://blogs.msdn.microsoft.com/ericlippert/2004/01/22/why-are-so-man… A StackOverflow q&a: https://stackoverflow.com/questions/268251/why-seal-a-class/268287
pizza234 · 2018-02-13
> 24 - 72 hours for a fairly critical and relatively easily solved security bug Let's see. How many microsoft employees would it take to change a lightbulb? ;-) https://blogs.msdn.microsoft.com/ericlippert/2003/10/28/how-many-micro… Highlight: > That initial five minutes of dev time translates into many person-weeks of work and enormous costs This is just to add an interesting article on top of the sibling comment from the MS employee; nothing's easy in the engineering of a large product.
gbacon · 2017-11-08
Related, with emphasis in original: > Determining whether a given predicate has a set of valuations for its variables which make it true is an NP-complete problem; actually finding the set of valuations is an NP-hard problem. Therefore, overload resolution in C# 3.0 is at the very least NP-hard. There is no known polynomial-time algorithm for any NP-complete or NP-hard problem and it is widely believed that there is none to be found, though that conjecture has yet to be proven. So our dream of fast lambda type analysis in C# 3.0 is almost certainly doomed, at least as long as we have the current rules for overload resolution. See Lambda Expressions vs. Anonymous Methods, Part Five[0] by Eric Lippert. [0]: https://blogs.msdn.microsoft.com/ericlippert/2007/03/28/lambda-express…
nitrogen · 2017-11-04
Part of it may be that in higher dimensions the bulk of a volume is concentrated near the surface. I found https://blogs.msdn.microsoft.com/ericlippert/2005/05/13/high-dimension… with a quick search.
munificent · 2017-09-12
:( That's because Go chose to reuse the loop variable in each iteration instead of binding a fresh one each time. C# figure out that was a mistake years ago and fixed it in 5.0 [1]. Dart has always bound a new variable in each iteration. I don't know why Go made the choice they did. [1]: https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-t…
danbruc · 2017-04-17
Eric Lippert, a former C# compiler developer, has a good blog post [1] discussing the reasoning and the difference between modulus and remainder. [1] https://blogs.msdn.microsoft.com/ericlippert/2011/12/05/whats-the-diff…
taspeotis · 2016-06-21
> you can create value types in the CLR (struct in C#), which are always stack allocated "always stack allocated" for certain values of "always" [1]. [1] https://blogs.msdn.microsoft.com/ericlippert/2010/09/30/the-truth-abou…
sclangdon · 2016-06-07
Good job OP. I personally found Eric Lippert's 6-part series (and playable Silverlight demo) on the subject fascinating. I didn't notice it referenced in your design document, so here it is. https://blogs.msdn.microsoft.com/ericlippert/tag/shadowcasting/
jguegant · 2016-05-14
Here take your rustwin point! I really like the explicit capture of C++'s lambdas more than the implicit one in most other languages (C#, Java, Python...) where you easily ends-up with a closure not referencing the expected variable. See: https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-t…
maxlybbert · 2016-12-16
I realized after I posted my last question that a language could convert an unexpected exception into some other notice that "something went wrong" (e.g., another exception). But if that behavior is ever triggered, it's not clear what you can do. You have a library reporting that (1) it detected an internal problem AND (2) it did not handle that problem. Any objects you have from that library might be affected, so you can't reliably call functions on them. If the library provides a way to deallocate its objects ( https://blogs.msdn.microsoft.com/oldnewthing/20060915-04/?p=29723 ), you can't trust that it will work. Letting the objects fall out of scope isn't even safe. By the way, you can get very close to this behavior today with `std::set_unexpected` ( http://www.cplusplus.com/reference/exception/set_unexpected/ ). That page says that the function you set as the unexpected handler must "end either by terminating (calling `terminate` or some other method, such as `exit` or `abort`) or by throwing an exception (even rethrowing the same exception again). If the exception thrown (or rethrown) is not in the function's dynamic-exception-specification but `bad_exception` is, a `bad_exception` is thrown" (emphasis added). * > Programs can already crash in enough ways, without C++ introducing more. ... When I see terminate() I know I have a problem. I essentially have to start using "grep" for every possible "throw" statement (hopefully finding something in…
DonHopkins · 2018-02-11
In the case of generics, C# got them right (but required changes to CLR 2.0) and then Java tried to copy the idea (without requiring any changes to the JVM) but fucked them up. Look up "type erasure": Java's underlying compiled classes weren't actually generic, and generics compiled down to "Object" and casts (which are less efficient, and can be subverted at runtime). Generics were implemented by the Java compiler, not the JVM runtime. https://stackoverflow.com/questions/31693/what-are-the-differences-bet… https://stackoverflow.com/questions/355060/c-sharp-vs-java-generics http://www.jprl.com/Blog/archive/development/2007/Aug-31.html http://www.artima.com/intv/generics2.html https://blogs.msdn.microsoft.com/ericlippert/2009/07/30/whats-the-diff…

Keyboard shortcuts

/Search
j kNext / previous blog
EnterOpen selected blog
vVisit the blog site
fFollow / unfollow
lSwitch grid / list view
dSwitch dark mode
g hHome
g pTop posts
g tTopics
g fFollowing
g lLiked
g yHistory
g qFAQ
EscBack / close