Site: http://blogs.msdn.com/b/ericlippert/ Link: http://blogs.msdn.com/ericlippert/rss.xml
by Eric Lippert via Fabulous Adventures In Coding on 12/29/2011 3:05:00 PM
OK, let's finish up this year and this series. We have an algorithm that can compute what cells in the zero octant are in view to a viewer at the origin when given a function that determines whether a given cell is opaque or transparent. It marks the visible points by calling an action with the visible cells. We would like that to work in any octant, and for the viewer at any point, not just the origin. We can solve the "viewer at any point" problem by imposing a coordinate transformation on th ...
[ read more ]
by Eric Lippert via Fabulous Adventures In Coding on 12/27/2011 6:05:00 PM
I hope you all had a pleasant Christmas and Boxing Day; we chose to not travel to see family this year and had a delightful time visiting friends. We'll finish up 2011 here with a bit more on shadowcasting, and then pick up with more C# language design facts and opinions in January. OK, so we've found the top and bottom cells in a particular column portion, bounded by a top and bottom vector. Now we have two tasks. First, all cells in that portion that are in the radius need to be marked as v ...
by Eric Lippert via Fabulous Adventures In Coding on 12/22/2011 5:18:00 PM
Last time we saw how many different ways there were to get the calculation of the top cell based on the top vector wrong. Today we'll take a briefer look at determining the bottom cell. We know from our discussion of last time that the right way to determine what is the top-most visible cell in a column portion is to consider where the top vector leaves the column. By similar logic, the right way to determine where the bottom-most cell is in a column portion is to look at where the bottom vecto ...
by Eric Lippert via Fabulous Adventures In Coding on 12/19/2011 4:06:00 PM
Before we get started, thanks for all the great comments to the previous couple of posts. I'll be updating the algorithm to try to make even better-looking circles of light based on the comments. Like I said, there's a lot of subtleties to these algorithms and I am just learning about them myself. To that end, in today's episode I am going to spend the entire prolix article analyzing a single division operation. You have been warned. Before we begin though, some jargon. A cell which is invisibl ...
by Eric Lippert via Fabulous Adventures In Coding on 12/15/2011 4:43:00 PM
I hope the basic idea of the shadow casting algorithm is now clear. Let's start to implement the thing. There are two main concerns to deal with. The easy one is "what should the interface to the computation look like?" The second is "how to implement it?" Let's deal with the easy one first; let's design the API. What does the caller need to provide? The coordinates of a central point The radius of the field of view Some way for the algorithm to know which cells are opaque What does the imp ...
by Eric Lippert via Fabulous Adventures In Coding on 12/12/2011 3:13:00 PM
I've always loved the "roguelike" games; perhaps you've played some of them. Those are the games where you get a top-down view of a tile-based world, and have as much real time as you like to make a choice of action. The canonical plot is to enter a dungeon, get to the bottom, retrieve the Amulet of Yendor, and make it back out of the dungeon with it. As you might expect, the original game with these characteristics was called "Rogue", and it has spawned many far more complex imitators. I'm par ...
by Eric Lippert via Fabulous Adventures In Coding on 12/8/2011 3:51:00 PM
In my earlier article from April 2011 on interface implementation I noted that C# supports a seldom-used feature called "interface re-implementation". This feature is useful when you need it but unfortunately is one of those features that can bite you if you use it incorrectly or accidentally. Every interface method of every interface you implement in a class or struct has to be "mapped" to a method in the type (either a method directly implemented by the type or a method that the type obtained ...
by Eric Lippert via Fabulous Adventures In Coding on 10/19/2011 9:00:00 PM
I am super excited to announce that the Roslyn project code is now sufficiently coherent that we can start showing it to customers! But I am getting ahead of myself somewhat. What is this "Roslyn" project? Here's the deal. We've got these great premiere languages for .NET development, C# and Visual Basic. Obviously the compilers need to do considerable lexical, syntactic and semantic analysis of the code in order to first off, produce IL out the back end of the compiler, and second, produce all ...
by Eric Lippert via Fabulous Adventures In Coding on 9/19/2011 5:18:00 PM
(Note: Not to be confused with Representation and Identity) Here's a question I got this morning: class Alpha<X> where X : class {}class Bravo<T, U> where T : class where U : T { Alpha<U> alpha;} This gives a compilation error stating that U cannot be used as a type argument for Alpha's type parameter X because U is not known to be a reference type. But surely U is known to be a reference type because U is constrained to be T, and T is constrained to ...
by Eric Lippert via Fabulous Adventures In Coding on 9/7/2011 5:58:00 PM
Well that was entirely predictable; as I said last time, if you ask ten developers for a definition of "type", you get ten different answers. The comments to the previous article make for fascinating reading! Here's my attempt at describing what "type" means to me as a compiler writer. I want to start by considering just the question of what a type is and not confuse that with how it is used. Fundamentally, a type in C# is a mathematical entity that obeys certain algebraic rules, just as natura ...
by Eric Lippert via Fabulous Adventures In Coding on 8/29/2011 2:33:00 PM
(Eric is out camping; this posting is prerecorded. I'll be back in the office after Labour Day.) The word "type" appears almost five thousand times in the C# 4 specification, and there is an entire chapter, chapter 4, dedicated to nothing but describing types. We start the specification by noting that C# is "type safe" and has "a unified type system" (*). We say that programs "declare" types, and that declared types can be organized by namespace. Clearly types are incredibly important to the de ...
by Eric Lippert via Fabulous Adventures In Coding on 7/19/2011 9:16:37 PM
Todays post is based on a question from StackOverflow; I liked it so much I figured hey, let's just blog it today. When you look at a string in C#, it looks to you like a collection of characters, end of story. But of course, behind the scenes there is a data structure in memory somewhere to implement that collection of characters. In the .NET CLR, strings are laid out in memory pretty much the same way that BSTRs were implemented in OLE Automation: as a word-aligned memory buffer consisting of ...
by Eric Lippert via Fabulous Adventures In Coding on 7/12/2011 7:19:00 PM
There are all kinds of interesting things in the Unicode standard. For example, the block of characters from U+A000 to U+A48F is for representing syllables in the "Yi script". Apparently it is a Chinese language writing system developed during the Tang Dynasty. A string drawn from this block has an unusual property; the string consists of just two characters, both the same: a repetition of character U+A0A2: string s = "??"; Or, if your browser can't hack the Yi script, that's the equivalent of ...
by Eric Lippert via Fabulous Adventures In Coding on 7/8/2011 4:24:51 PM
[No computer stuff today; just some fun for a Friday.] British fantasy author Neil Gaiman was in Seattle recently. I was so disappointed that I did not find out about it until it was too late to attend his event. It's a pity I missed it because I've been wanting for years to ask Neil Gaiman if he likes soup. To explain why, we'll have to go back to 1993. Remember 1993? The first wave of HTTP-based document servers were going up on the internet; it was the beginning of the internet as we know ...
by Eric Lippert via Fabulous Adventures In Coding on 6/23/2011 2:01:00 PM
"Ref returns" are the subject of another great question from StackOverflow that I thought I might share with a larger audience. Ever since C# 1.0 you've been able to create an "alias" to a variable by passing a "ref to a variable" to certain methods: static void M(ref int x){ x = 123;}...int y = 456;M(ref y); Despite their different names, "x" and "y" are now aliases for each other; they both refer to the same storage location. When x is changed, y changes too because they are ...
by Eric Lippert via Fabulous Adventures In Coding on 6/16/2011 2:03:00 PM
So what does "volatile" mean, anyway? Misinformation abounds on this subject. First off, so as to not bury the lead: in C# the rules have been carefully designed so that every volatile field read and write is also atomic. (Of course the converse does not follow; it is perfectly legal for an operation to be atomic without it being "volatile", whatever that means.) The way this is achieved is simple; the rules of C# only permit you to annotate fields with "volatile" if the field also has a type ...
by Eric Lippert via Fabulous Adventures In Coding on 5/31/2011 9:56:24 PM
Last time we established that an "atomic" read or write of a variable means that in multithreaded scenarios, you never end up with "halfway mutated" values in the variable. The variable goes from unmutated to mutated directly, with no intervening state. I also talked a bit about how making fields of a struct "readonly" has no effect on atomicity; when the struct is copied around, it may be copied around four bytes at a time regardless of whether its fields are marked as "readonly" or not. There ...
by Eric Lippert via Fabulous Adventures In Coding on 5/23/2011 2:47:00 PM
Here's a common problem that we face in the compiler realm all the time: you want to make an efficient immutable lookup table for mapping names to "symbols". This is in a sense the primary problem that the compiler has to solve; someone says "x = y + z;" and we have to figure out what "x", "y" and "z" mean before we can do any more analysis. An obvious way to do that is to figure out all the name-to-symbol mappings for a particular declaration space once, ahead of time, stuff the results into a ...
by Eric Lippert via Fabulous Adventures In Coding on 5/19/2011 3:19:00 PM
(This is the fourth and final part of a series on the corner cases of optional arguments in C# 4; part three is here.) Last time we discussed how some people think that an optional argument generates a bunch of overloads that call each other. People also sometimes incorrectly think that void M(string format, bool b = false) { Console.WriteLine(format, b); } is actually a syntactic sugar for something morally like: void M(string format, bool? b){ bool realB = b ?? false; Cons ...
by Eric Lippert via Fabulous Adventures In Coding on 5/16/2011 2:50:00 PM
(This is part three of a series on the corner cases of optional arguments in C# 4; part two is here. Part four is here.) A lot of people seem to think that this: void M(string x, bool y = false) { ... whatever ... } is actually a syntactic sugar for the way you used to have to write this in C#, which is: void M(string x) { M(x, false); }void M(string x, bool y) { ... whatever ... } But it is not. The syntactic sugar here is not on the declaration side, but rather on the call side. There is only ...
by Eric Lippert via Fabulous Adventures In Coding on 5/12/2011 4:29:35 PM
(This is part two of a series on the corner cases of optional arguments in C# 4. Part one is here. Part three is here. This portion of the series was inspired by this StackOverflow question.) Last time we saw that the declared optional arguments of an interface method need not be optional arguments of an implementing class method. That seems potentially confusing; why not require that an implementing method on a class exactly repeat the optional arguments of the declaration? Because the cure is ...
by Eric Lippert via Fabulous Adventures In Coding on 5/9/2011 2:29:00 PM
(This is part one of a series on the corner cases of optional arguments in C# 4. Part two is here.) In C# 4.0 we added "optional arguments"; that is, you can state in the declaration of a method's parameter that if certain arguments are omitted, then constants can be substituted for them: void M(int x = 123, int y = 456) { } can be called as M(), M(0) and M(0, 1). The first two cases are treated as though you'd said M(123, 456) and M(0, 456) respectively. This was a controversial feature for th ...
by Eric Lippert via Fabulous Adventures In Coding on 4/20/2011 5:37:52 PM
One of the most controversial features we've ever added was implicitly typed local variables, aka "var". Even now, years later, I still see articles debating the pros and cons of the feature. I'm often asked what my opinion is, so here you go. Let's first establish what the purpose of code is in the first place. For this article, the purpose of code is to create value by solving a business problem. Now, sure, that's not the purpose of all code. The purpose of the assembler I wrote for my CS 24 ...
by Eric Lippert via Fabulous Adventures In Coding on 4/13/2011 4:00:00 PM
Good morning everyone! I am pleased to tell you that the C# and VB teams are announcing a "refresh" of the async Community Technology Preview at MIX11 today, and that it is as of right now available on the Async CTP site. Recall that the CTP release is an early look at our thinking for the proposed async language features so that we can get your feedback. Rather than posting feedback here, please let us know what you think on the Async Forum. We've gotten a lot of good feedback ...
by Eric Lippert via Fabulous Adventures In Coding on 4/4/2011 3:14:57 PM
Today, another question from StackOverflow, and again, presented as a dialogue as is my wont. The MSDN documentation for List<T> says that the class is declared as public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable Does List<T> really implement all those interfaces? Yes. Why so m ...
by Eric Lippert via Fabulous Adventures In Coding on 4/1/2011 8:06:00 AM
Last time I discussed how the compound assignment operators of the form “x op= y” have some perhaps unobvious behaviours in C#, namely: (1) though logically this is expanded as “x = x op y”, x is only evaluated once(2) for built-in operators, if necessary, a cast is inserted, so that this is analyzed as “x = (T)(x op y)” (3) for built-in operators, if “x = y” would be illegal then so is “x op= y” I am pleased to announce that we are at ...
by Eric Lippert via Fabulous Adventures In Coding on 3/29/2011 1:24:00 PM
When people try to explain the compound assignment operators += –= *= /= %= <<= >>= &= |= ^= to new C# programmers they usually say something like “x += 10; is just a short way of writing x = x + 10;”. Now, though that is undoubtedly true for a local variable x of type int, that’s not the whole story, not by far. There are actually many subtle details to the compound assignment operators that you might not appreciate at first glance. First off, suppose the expression on the lef ...
by Eric Lippert via Fabulous Adventures In Coding on 3/24/2011 2:10:00 PM
Last time we saw how you could emulate virtual methods in a language that only had static methods by creating fields of delegate type, and then choosing what delegates go into the fields. However, this is not very space-efficient. Suppose there were a hundred virtual methods on Animal instead of two. That means that every class derived from Animal has a hundred fields, and in most of them, those fields are exactly the same, all the time. You make three hundred giraffes and each one of them will ...
by Eric Lippert via Fabulous Adventures In Coding on 3/21/2011 2:08:00 PM
So far we've gotten rid of instance methods; they're just static methods that take a hidden "this" parameter. But virtual methods are a bit harder. We're going to implement virtual methods as fields of delegate type containing delegates to static methods. abstract class Animal{ public Func<Animal, string> Complain; public Func<Animal, string> MakeNoise; public static string MakeNoise(Animal _this) { return ""; }} OK, everything seems f ...
by Eric Lippert via Fabulous Adventures In Coding on 3/17/2011 1:42:00 PM
If you've been in this business for any length of time you've undoubtedly seen some of the vast literature on "design patterns" -- you know, those standard solutions to common problems with names like "factory" and "observer" and "singleton" and "iterator" and "composite" and "adaptor" and "decorator" and... and so on. It is frequently useful to be able to take advantage of the analysis and design skills of others who have already given considerable thought to codifying patterns that solve comm ...
by Eric Lippert via Fabulous Adventures In Coding on 3/14/2011 2:20:00 PM
Suppose you have an immutable value type that is also disposable. Perhaps it represents some sort of handle. struct MyHandle : IDisposable{ public MyHandle(int handle) : this() { this.Handle = handle; } public int Handle { get; private set; } public void Dispose() { Somehow.Close(this.Handle); }} You might think hey, you know, I'll decrease my probability of clos ...
by Eric Lippert via Fabulous Adventures In Coding on 3/10/2011 5:50:00 PM
Here's a handy type I whipped up when I was translating some complex pointer-manipulation code from C to C#. It lets you make a safe "managed pointer" to the interior of an array. You get all the operations you can do on an unmanaged pointer: you can dereference it as an offset into an array, do addition and subtraction, compare two pointers for equality or inequality, and represent a null pointer. But unlike the corresponding unsafe code, this code doesn't mess up the garbage collector and wil ...
by Eric Lippert via Fabulous Adventures In Coding on 3/7/2011 5:50:35 PM
Writing code in C# is really all about the programmatic manipulation of values. A value is either of a value type, like an integer or a decimal, or it's a reference to an instance of a reference type, like a string or an exception. Values you manipulate always have a storage location that stores the value; those storage locations are called "variables". Often in a C# program you manipulate the values by describing which variable you're interested in. In C# there are three basic operations you ...
by Eric Lippert via Fabulous Adventures In Coding on 3/3/2011 6:41:00 PM
As long-time readers of this blog know, I am often asked why a particular hunk of bad-smelling code does not produce a compiler warning. "Why not?" questions are inherently hard to answer because they turn causation on its head; normally we ask what caused a particular thing to happen, not what caused a particular thing to not happen. Therefore, rather than attack that question directly I like to rephrase the question into questions about the proposed feature. (A warning is of course a feature ...
by Eric Lippert via Fabulous Adventures In Coding on 2/28/2011 2:39:00 PM
"The code is more what you'd call guidelines than actual rules" - truer words were never spoken. It's important when writing code to understand what are vague "guidelines" that should be followed but can be broken or fudged, and what are crisp "rules" that have serious negative consequences for correctness and robustness. I often get questions about the rules and guidelines for GetHashCode, so I thought I might summarize them here. What is GetHashCode used for? It is by design useful for only ...
by Eric Lippert via Fabulous Adventures In Coding on 2/24/2011 2:31:00 PM
Whether we have a "never" return type or not, we need to be able to determine when the end point of a method is unreachable for error reporting in methods that have non-void return type. The compiler is pretty clever about working that out; it can handle situations like int M(){ try { while(true) N(); } catch(Exception ex) { throw new WrappingException(ex); }} The compiler knows that N either throws or it doesn't, and ...
by Eric Lippert via Fabulous Adventures In Coding on 2/21/2011 2:59:00 PM
Can you find a lambda expression that can be implicitly converted to Func<T> for any possible T? . . . . . . . . . . . Hint: The same lambda is convertible to Action as well. . . . . . . . . . Func<int> function = () => { throw new Exception(); }; The rule for assigning lambdas to delegates that return int is not "the body must return an int". Rather, the rules are: * All returns in the block must return an expression convertible to int.* The end point of the block must not be re ...
by Eric Lippert via Fabulous Adventures In Coding on 2/17/2011 2:36:00 PM
Occasionally when I'm debugging the compiler or responding to a user question I'll need to quickly take apart the bits of a double-precision floating point number. Doing so is a bit of a pain, so I've whipped up some quick code that takes a double and tells you all the salient facts about it. I present it here, should you have any use for it yourself. (Note that this code was built for comfort, not speed; it is more than fast enough for my purposes so I've spent zero time optimizing it.) To und ...
by Eric Lippert via Fabulous Adventures In Coding on 2/14/2011 2:29:00 PM
No one I know at Microsoft asks those godawful "lateral-thinking puzzle" interview questions anymore. Maybe someone still does, I don't know. But rumour has it that a lot of companies are still following the Microsoft lead from the 1990s in their interviews. In that tradition, I present a sequel to Keith Michaels' 2003 exercise in counterfactual reasoning. Once more, we dare to ask the question "how well would the late Nobel-Prize-winning physicist Dr. Richard P. Feynman do in a technical inter ...
by Eric Lippert via Fabulous Adventures In Coding on 2/10/2011 2:54:00 PM
Before we get into today's topic, a quick update on my posting from last year about Roslyn jobs. We have gotten a lot of good leads and made some hires but we still have positions open, both on the Roslyn team and on the larger Visual Studio team. For details, see this post on the Visual Studio blog. Again, please do not send me resumes directly; send them via the usual career site. Thanks! Here's a recent question I got from a reader: what is the correct analysis of this little problem i ...
by Eric Lippert via Fabulous Adventures In Coding on 2/7/2011 2:51:00 PM
"Can a property or method really be marked as both abstract and override?" one of my coworkers just asked me. My initial gut response was "of course not!" but as it turns out, the Roslyn codebase itself has a property getter marked as both abstract and override. (Which is why they were asking in the first place.) I thought about it a bit more and reconsidered. This pattern is quite rare, but it is perfectly legal and even sensible. The way it came about in our codebase is that we have a large, ...
by Eric Lippert via Fabulous Adventures In Coding on 2/3/2011 2:55:00 PM
Here's a pattern you see all the time in C#: class Frob : IComparable<Frob> At first glance you might ask yourself why this is not a "circular" definition; after all, you're not allowed to say "class Frob : Frob"(*). However, upon deeper reflection that makes perfect sense; a Frob is something that can be compared to another Frob. There's not actually a real circularity there. This pattern can be genericized further: class SortedList<T> where T : IComparable<T> Again, it might ...
by Eric Lippert via Fabulous Adventures In Coding on 1/31/2011 2:44:00 PM
One more easy one. I want to "sort" a list into a random, shuffled order. I can do that by simply randomizing whether any two elements are greater than, less than, or equal to each other: myList.Sort((x, y) => (new Random()).Next(-1, 2)); That generates a random -1, 0 or 1 for every comparison, right? So it will sort the list into random order, right? . . . . . . . There are multiple defects here. First off, clearly this violates all our rules for comparison functions. It does not produce a ...
by Eric Lippert via Fabulous Adventures In Coding on 1/27/2011 2:56:00 PM
Did you notice how last time my length comparison on strings was unnecessarily verbose? I could have written it like this: static int ByLength(string x, string y){ if (x == null && y == null) return 0: if (x == null) return -1; if (y == null) return 1; return CompareInts(x.Length, y.Length);}static int CompareInts(int x, int y){ // Positive if x is larger, negative if y is larger, zero if equal return x - y; } static Comparison<T> ThenBy<T&g ...
by Eric Lippert via Fabulous Adventures In Coding on 1/24/2011 2:43:00 PM
Suppose I want to sort a bunch of strings into order first by length, and then, once they are sorted by length, sort each group that is the same length by some other comparison. We can easily build such a device with higher-order programming: static Comparison<string> FirstByLength(Comparison<string> thenBy){ return (string x, string y) => { // Null strings are sorted before zero-length strings; remember, we need to provide a total ordering. &nb ...
by Eric Lippert via Fabulous Adventures In Coding on 1/20/2011 2:16:00 PM
The mutable List<T> class provides an in-place sort method which can take a comparison delegate. It's quite handy to be able to sort a list into order by being able to compare any two elements, but you have to make sure you get it right. First off, what are the requirements of the comparison delegate? They are clearly documented: the comparison takes two elements and returns a 32 bit signed integer. If the first element is greater than the second then the integer is greater than zero. If ...
by Eric Lippert via Fabulous Adventures In Coding on 1/17/2011 7:25:00 PM
Holy goodness, did you guys ever find a lot of additional ways in which an "eliminate variable" refactoring can go wrong. Just a few of your observations: (again, in every case, "x" is eliminated.) Any situation in which x is being treated as a variable rather than a value will pose a problem. Some obvious ones, like if x is on the left side of an assignment, or the target of a ++, or used as a "ref" or "out" parameter are straightforward. But there are some situations in which it is a bit surp ...
by Eric Lippert via Fabulous Adventures In Coding on 1/13/2011 3:01:00 PM
My colleague Kevin works on (among many other things) the refactoring engine in the C# IDE. He and I were at the end of last year discussing the possible cases for a hypothetical "eliminate variable" refactoring. I thought that it might be of interest to you guys to get a glimpse of the sorts of issues that the IDE team faces on a daily basis. First off, what is the "eliminate variable" refactoring? It is seemingly straightforward, but as we'll see, appearances can be deceiving. Suppose you hav ...
by Eric Lippert via Fabulous Adventures In Coding on 12/20/2010 2:30:00 PM
Suppose you use an anonymous type in C#: var x = new { A = "hello", B = 123.456 }; Ever taken a look at what code is generated for that thing? If you crack open the assembly with ILDASM or some other tool, you'll see this mess in the top-level type definitions .class '<>f__AnonymousType0`2'<'<A>j__TPar','<B>j__TPar'> What the heck? Let's clean that up a bit. We've mangled the names so that you are guaranteed that you cannot possibly accidentally use this thing "as is" fr ...
by Eric Lippert via Fabulous Adventures In Coding on 12/13/2010 3:00:00 PM
People sometimes ask me why you can’t do this in C#: class GrandBase{ public virtual void M() { Console.WriteLine("GB"); }}class Base : GrandBase{ public override void M() { Console.WriteLine("B"); }}class Derived : Base{ public override void M() { Console.WriteLine("D"); base.base.M(); // illegal! }} The author of the most-derived class here wishes to call its GrandBase implementation of M, rather than the Base implementation ...
by Eric Lippert via Fabulous Adventures In Coding on 11/29/2010 6:16:30 PM
From the sublime level of continuation passing style we go back to the mundane level of twiddling individual bits. int i = SomeBagOfBits();ulong u = SomeOtherBagOfBits();ulong result = u | i; // combine them together Whoops, that's an error. "Operator | cannot be applied to operands of type int and ulong." There are bitwise-or operators defined on int, uint, long and ulong, but none between int and ulong. You cannot use the int version because the ulong might not fit, and you cannot use the ulo ...
by Eric Lippert via Fabulous Adventures In Coding on 11/23/2010 2:31:00 PM
(In this post I'll be talking about exogenous, vexing, boneheaded and fatal exceptions. See this post for a definition of those terms.) If your process experiences an unhandled exception then clearly something bad and unanticipated has happened. If its a fatal exception then you're already in no position to save the process; it is going down. You might as well leave it unhandled, or just log it and rethrow it. If it had been anticipated because it's a vexing or exogenous exception then there wo ...
by Eric Lippert via Fabulous Adventures In Coding on 11/19/2010 4:47:53 PM
Resuming where we left off (ha ha ha!) after that brief interruption: exception handling in "resumable" methods like our coroutine-like asynchronous methods is more than a little bit weird. To get a sense of how weird it is, you might want to first refresh your memory of my recent series on the design of iterator blocks, particularly the post about the difference between a "push" model and a "pull" model. Briefly though: In a regular code block, a try block surrounding a normal "synchronous" ca ...
by Eric Lippert via Fabulous Adventures In Coding on 11/15/2010 2:45:00 PM
A brief digression from C# 5 to talk about C# 4: the annotated C# 4 specification is now available in book form from Addison-Wesley. It is of course handy to have a specification in book form, particularly if you're going to while away the hours with the book sitting by a warm fire. (It's hundreds of pages long; you can keep a fire going for hours.) But the real value-add of this edition over the downloadable version is that the print version is heavily annotated by numerous people who know a t ...
by Eric Lippert via Fabulous Adventures In Coding on 11/11/2010 2:54:00 PM
A number of people have asked me what motivates the design decision to require any method that contains an "await" expression to be prefixed with the contextual keyword "async". Like any design decision there are pros and cons here that have to be evaluated in the context of many different competing and incompossible principles. There's not going to be a slam-dunk solution here that meets every criterion or delights everyone. We're always looking for an attainable compromise, not for unattaina ...
by Eric Lippert via Fabulous Adventures In Coding on 11/8/2010 2:26:00 PM
Suppose a city has a whole bunch of bank branches, each of which has a whole bunch of tellers and one gofer. There are a whole bunch of customers in the city, each of whom wants to withdraw a whole bunch of money from the bank at some varying time throughout the day. The algorithm goes like this: A customer finds the nearest bank branch and evaluates its line. If the line is out the door, then the customer goes to another bank branch. This continues until they either find one with a short enoug ...
by Eric Lippert via Fabulous Adventures In Coding on 11/4/2010 1:23:00 PM
Today I want to talk about asynchrony that does not involve any multithreading whatsoever. People keep on asking me "but how is it possible to have asynchrony without multithreading?" A strange question to ask because you probably already know the answer. Let me turn the question around: how is it possible to have multitasking without multiple CPUs? You can't do two things "at the same time" if there's only one thing doing the work! But you already know the answer to that: multitasking on a si ...
by Eric Lippert via Fabulous Adventures In Coding on 11/1/2010 1:34:00 PM
I was walking to my bus the other morning at about 6:45 AM. Just as I was about to turn onto 45th street, a young man, shirtless, covered in blood ran down 45th at considerable speed right in front of me. Behind him was another fellow, wielding a baseball bat. My initial thought was "holy goodness, I have to call the police right now!" Then I saw that the guy with the baseball bat was himself being chased by Count Dracula, a small horde of zombies, a band of pirates, one medieval knight, and b ...
by Eric Lippert via Fabulous Adventures In Coding on 10/29/2010 1:44:00 PM
I want to start by being absolutely positively clear about two things, because our usability research has shown this to be confusing. Remember our little program from last time? async void ArchiveDocuments(List<Url> urls){ Task archive = null; for(int i = 0; i < urls.Count; ++i) { var document = await FetchAsync(urls[i]); if (archive != null) await archive; archive = ArchiveAsync(docu ...
by Eric Lippert via Fabulous Adventures In Coding on 10/28/2010 6:30:00 PM
The designers of C# 2.0 realized that writing iterator logic was painful. So they added iterator blocks. That way the compiler could figure out how to build a state machine that could store the continuation - the “what comes next” - in state somewhere, hidden behind the scenes, so that you don’t have to write that code. They also realized that writing little methods that make use of local variables was painful. So they added anonymous methods. That way the compiler could figure out how to hois ...
by Eric Lippert via Fabulous Adventures In Coding on 10/27/2010 1:45:00 PM
Today is when things are going to get really long and confusing. But we'll make it through somehow. Consider the following task: you’ve got a list of URLs. You want to fetch the document associated with each URL. (Let’s suppose for the sake of argument that this always succeeds.) You then want to make a copy of the document on your network attached tape drive storage, because you’re old school. Totally straightforward. Two lines of code. Hardly worth making a method out of: void ArchiveDocume ...
by Eric Lippert via Fabulous Adventures In Coding on 10/26/2010 1:15:00 PM
The obvious question at this point is: if CPS is so awesome then why don’t we use it all the time? Why have most professional developers never heard of it, or, those who have, think of it as something only those crazy Scheme programmers do? First of all, it is simply hard for most people who are used to thinking about subroutines, loops, try-catch-finally and so on to reason about delegates being used for control flow in this way. I am reviewing my notes on CPS from CS442 right now and I see t ...
by Eric Lippert via Fabulous Adventures In Coding on 10/25/2010 1:40:00 PM
Last time I sketched briefly how one might implement interesting control flows like try-catch using continuations; as we saw, the actual implementations of Try and Throw are trivial once you have CPS. I'm sure that you could extend that work to implement try-catch-finally. Or, another basic exercise when learning about CPS you might try is to implement coroutines. What’s a coroutine? Excellent question! Cast your mind back to the days of cooperative multitasking in Windows 3. The idea of coop ...
by Eric Lippert via Fabulous Adventures In Coding on 10/22/2010 1:29:00 PM
Last time on Fabulous Adventures: “But we can construct arbitrarily complex control flows by keeping track of multiple continuations and deciding which one gets to go next.” Let’s look at an example of something more complex than a conditional. Consider a simplified version of “try-catch”, where there is no expression to the throw. A throw is simply a non-local goto that goes to the nearest enclosing catch. The traditional way to think about void Q(){ try { B(A ...
by Eric Lippert via Fabulous Adventures In Coding on 10/21/2010 1:38:00 PM
Good morning fabulous readers, let me just start by saying that this is going to get really long and really complicated but it will all pay off in the end. I’m also going to be posting on an accelerated schedule, more than my usual two posts per week. (It’ll eventually become clear why I'm doing all of this, he said mysteriously. Remember, suspense is a sign of a quality blog.) I want to talk quite a bit about a subject that I first discussed briefly a few years back, namely, Continuation Pass ...
by Eric Lippert via Fabulous Adventures In Coding on 10/11/2010 3:53:00 PM
Here's another myth about value types that I sometimes hear: "Obviously, using the new operator on a reference type allocates memory on the heap. But a value type is called a value type because it stores its own value, not a reference to its value. Therefore, using the new operator on a value type allocates no additional memory. Rather, the memory already allocated for the value is used." That seems plausible, right? Suppose you have an assignment to, say, a field s of type S: s = new S(123, 45 ...
by Eric Lippert via Fabulous Adventures In Coding on 10/7/2010 5:12:00 PM
As i was saying last time, the nice thing about "no backtracking" is that it makes the language much easier to understand. Simple rules benefit both the compiler and the code reader; both are attempting to read the code to make sense of it. It is not always a good idea to take advantage of the compiler's ability to search a large space if that makes it harder for a human to understand the code. Suppose you have something like this mess: (*) namespace XYZ.DEF{ public cla ...
by Eric Lippert via Fabulous Adventures In Coding on 10/4/2010 4:56:00 PM
A number of the articles I’ve published over the years involve “backtracking” algorithms; most recently my series on how to solve Sudoku puzzles (and more generally, all graph colouring problems) by backtracking. The idea of a backtracking algorithm is really simple and powerful: when faced with a choice, try every possibility. If all of them go wrong, backtrack to the previous choice and try a different possibility. Backtracking algorithms are essentially a depth-first search of the space of p ...
by Eric Lippert via Fabulous Adventures In Coding on 9/9/2010 1:58:00 PM
I'm back from my various travels, refreshed and ready for more fabulous adventures in coding. A while back I did a coding challenge for you all: to turn a sequence of strings into a fancy comma-separated list. You might also recall that I did a bit on how to generate all possible arbitrary trees, which I notated with a simple bracing format. Today, let's combine those two problems. What I want to do is create a function which takes an arbitrary tree where each node has some string data, and tu ...
by Eric Lippert via Fabulous Adventures In Coding on 7/29/2010 1:40:00 PM
I said last time that I was interested in finding colourings for graphs that have lots of fully connected subgraphs, aka "cliques". For instance, I'd like to find a four-colouring for this sixteen-node graph: Yuck. What a mess. What this graph is doing a bad job of conveying is that there are twelve fully connected subsets. {0, 1, 2, 3} forms a clique. So does {0, 1, 4, 5}. And so does {0, 4, 8, 12}. It would be great if I had a better way to display full connectedness. How about this: I'll j ...
by Eric Lippert via Fabulous Adventures In Coding on 7/26/2010 3:20:00 PM
Let's give it a try. Can we colour South America with only four colours? Let's start by stating what all the edges are in the graph of South America: const int Brazil = 0;const int FrenchGuiana = 1;const int Suriname = 2;const int Guyana = 3; const int Venezuala = 4;const int Colombia = 5;const int Ecuador = 6;const int Peru = 7;const int Chile = 8;const int Bolivia = 9;const int Paraguay = 10;const int Uruguay = 11;const int Argentina = 12;var SA = new Dictionary<int, int[]>(){ &nb ...
by Eric Lippert via Fabulous Adventures In Coding on 7/22/2010 1:54:00 PM
OK, we've got our basic data structures in place. Graph colouring is a very well-studied problem. It's known to be NP-complete for arbitrary graphs, so (assuming that P!=NP) we're not going to find an always-fast algorithm for colouring an arbitrary graph. However, for typical graphs that we encounter in the wild, the following simple algorithm is pretty good. Start by saying that every node can be every possible colour. Then: 1) Do you have a single possible colouring for every node in t ...
by Eric Lippert via Fabulous Adventures In Coding on 7/15/2010 3:09:00 PM
Before I begin a quick note: congratulations and best wishes to David Johnson, currently the president of my alma mater, the University of Waterloo. The Queen has appointed him to be the next Governor General of Canada come this October. For those of you unfamiliar with the Canadian political structure, Queen Elizabeth is the sovereign ruler Canada; the Governor General acts as her direct representative in Canada and therefore has the (mostly ceremonial, but some real) powers of a head of state ...
by Eric Lippert via Fabulous Adventures In Coding on 7/12/2010 3:15:00 PM
As regular readers know, I'm interested in learning how to change my C# programming style to emphasize more concepts from functional programming, like use of immutable rather than mutable data structures and use of declarative control flow like LINQ queries instead of imperative control flow in the form of loops. I thought I'd solve a fairly straightforward problem using a mix of immutable and mutable, declarative and imperative styles to indicate when each is useful and appropriate. I pic ...
by Eric Lippert via Fabulous Adventures In Coding on 6/28/2010 3:06:00 PM
And here we have yet another post inspired by a question on StackOverflow: how do you compute the Cartesian product of arbitrarily many sequences using LINQ? UPDATE: Ian Griffiths has an interesting series of articles that approaches this question in considerably more depth than I do; check it out! First off, let's make sure that we know what we're talking about. I'll notate sequences as ordered sets {a, b, c, d,...}. The Cartesian product of two sequences S1 and S2 is the sequence of all possi ...
by Eric Lippert via Fabulous Adventures In Coding on 6/14/2010 3:40:00 PM
Another interesting question from StackOverflow. That thing is a gold mine for blog topics. Consider the following: class B{ public int X() { return 123; }}class D : B{ new protected int X() { return 456; }}...
by Eric Lippert via Fabulous Adventures In Coding on 5/27/2010 1:55:00 PM
Another interesting question from StackOverflow. Consider the following unfortunate situation: object result;bool isDecimal = GetAmount(out result);decimal amount = (decimal)(isDecimal ? result : 0); The developer who wrote this code was quite surprised to discover that it compiles and then throws “invalid cast exception” if the alternative branch is taken. Anyone see why? In regular algebra, multiplication is “distributive” over addition. That is q * (r + s) is the same as q * r + q * s. The ...
by Eric Lippert via Fabulous Adventures In Coding on 5/24/2010 1:24:00 PM
We seem to have a bit of a performance problem here. We could slap a profiler on it, and normally I’d recommend just that. But in this case, let’s solve this problem by thinking. Suppose we’re trying to work out a problem in our previous grammar, say, S[6]. That requires us to work out, among other things, PARENEND[5], BRACKETEND[5], and so on, each of which requires us to work out S[4]. In short, we work out S[4] four times for every time we work out S[6]. Each one of those w ...
by Eric Lippert via Fabulous Adventures In Coding on 4/22/2010 2:05:00 PM
Last time we talked about how the number of binary trees with n nodes is C(n), where C(n) is the nth Catalan number. I asked if there were more or fewer trees – not restricted to binary trees – of size n than there are binary trees of size n. If you worked it out, the answer might have surprised you; it is certainly not immediately obvious. First off, a common response I get to this question is immediately "well, since binary trees are a special case of arbitrary trees, there must be more arbit ...
by Eric Lippert via Fabulous Adventures In Coding on 4/19/2010 1:34:00 PM
The other day I wrote a little algorithm that did some operation on binary trees. I wanted to test it. I whipped up a few little test cases and it seemed fine, but I wasn’t quite satisfied. I was pretty confident, but maybe there was some odd binary tree topology that I hadn’t considered which would cause a bug. I reasoned that there have got to be only a finite number of binary tree topologies of a given size. I’ll just try all of them. Before I go on, I need a compact notation for a binary tr ...
by Eric Lippert via Fabulous Adventures In Coding on 4/12/2010 1:53:00 PM
Yet another amusing question from StackOverflow: is there a difference between “return something;” and “return (something);” in C#? In practice, there is no difference. In theory there could be a difference. There are three interesting points in the C# specification where this could present a problem. First, conversion of anonymous functions to delegate types and expression trees. Consider the following: Func<int> F1() { return ()=>1; } Func<int> F2() { return (()=>1); } ...
by Eric Lippert via Fabulous Adventures In Coding on 4/8/2010 1:37:00 PM
The DateTime struct represents dates as a 64 bit number that measures the number of “ticks” since a particular start date. Ten million ticks equals one second. That’s a quite high degree of precision. You can represent dates and times to sub-microsecond accuracy with a DateTime, which is typically more precision than you need. Not always, of course; on modern hardware you can probably execute a couple hundred instructions in one tick, and therefore if you want timings that are at the level of p ...
by Eric Lippert via Fabulous Adventures In Coding on 4/1/2010 1:26:00 PM
As I’m sure you know by now, we are done implementing C# 4. We’ve added support for interoperability with dynamic languages and legacy object models, named and optional parameters, the ability to “link” against interfaces from a Primary Interop Assembly, and my favourite feature, covariance and contravariance of interface and delegate types. Now, sometimes we manage to find time in the schedule to fit in small additional features that do not directly align with the larger “theme” of the release ...
by Eric Lippert via Fabulous Adventures In Coding on 3/29/2010 1:16:00 PM
UPDATE: I have rewritten this article based on new information I’ve just learned. I should have looked at the design notes archive first! Here’s a crazy-seeming but honest-to-goodness real customer scenario that got reported to me recently. There are three DLLs involved, Alpha.DLL, Bravo.DLL and Charlie.DLL. The classes in each are: public class Alpha // In Alpha.DLL{ public virtual void M() { Console.WriteLine("Alpha"); }} public class Bravo: Alpha // In Bra ...
by Eric Lippert via Fabulous Adventures In Coding on 3/18/2010 1:56:00 PM
Part Four: Making the problem worse I said earlier that the fundamental reason for namespaces in the first place was organization of types into a hierarchy, not separation of two things with similar names. But suppose you are putting something into a namespace because you have two things that are of the same name and need to be kept separate. Suppose you reason “I’m going to put List into its own namespace because List could conflict with another class named List. The user needs to be a ...
by Eric Lippert via Fabulous Adventures In Coding on 3/15/2010 1:53:00 PM
Part Three: Bad hierarchical design The reason we humans invented hierarchies in the first place is to organize a complicated body of stuff such that there’s a well-defined place for everything. Any time you see a hierarchy where there are two levels with the same name, something is messed up in the design of that hierarchy. And any time you see a hierarchy where one of the interior nodes has a single child, again, something is probably messed up. Krzysztof points out in the annotated Framework ...
by Eric Lippert via Fabulous Adventures In Coding on 3/11/2010 6:51:00 PM
Part Two: Machine-generated code: You write namespace Foo{ public sealed class Foo { public string Blah(int x) { … } } } You take this code and run a third-party “decorator” tool over it that makes your class into a more colourful class: // Machine-generated code:namespace Foo{ public sealed class ColorFoo { public ColorFoo(Foo.Foo foo, System.Drawing.Color color) { innerFoo = foo; ...
by Eric Lippert via Fabulous Adventures In Coding on 3/9/2010 2:52:00 PM
The Framework Design Guidelines say in section 3.4 “do not use the same name for a namespace and a type in that namespace”. (*) That is: namespace MyContainers.List{ public class List { … }} Why is this badness? Oh, let me count the ways. Part One: Collisions amongst referenced assemblies: You can get yourself into situations where you think you are referring to one thing but in fact are referring to something else. Suppose you end up in this unfortunate situation: you are wri ...
by Eric Lippert via Fabulous Adventures In Coding on 3/4/2010 2:33:00 PM
A recent user question: I have code that maintains a queue of pending work items waiting to be completed on various different worker threads. In certain unfortunate fatal error situations I complete each of these by throwing an exception. Can I create just one exception object? Are there any issues throwing the same exception object multiple times on multiple threads? Anyone who has ever seen this in a code review knows the answer: catch(Exception ex){ Logger.Log(ex);   ...
by Eric Lippert via Fabulous Adventures In Coding on 2/25/2010 2:59:00 PM
Suppose you’re shutting down the worker thread we were talking about last time, and it throws an exception? What happens? Badness, that’s what. What to do about it? As in our previous discussion, it is better to not be in this situation in the first place: write the worker code so that it does not throw. If you cannot do that, then you have two choices: handle the exception, or don't handle the exception. Suppose you don't handle the exception. As of I think CLR v2, an unhandled exception in a ...
by Eric Lippert via Fabulous Adventures In Coding on 2/22/2010 2:41:00 PM
The other day, six years ago, I was was talking a bit about how to decide whether to keep waiting for a bus, or to give up and walk. It led to a quite interesting discussion on the old JoS forum. But what if the choice isn’t “wait for a bit then give up”, instead it is “wait for a bit, and then take an axe to the thread”? A pattern I occasionally see is something like I’ve got a worker thread that I started up, I ask it to shut down, and then I wait for it to do so. If it doesn’t shut down soo ...
by Eric Lippert via Fabulous Adventures In Coding on 2/18/2010 2:22:00 PM
The conditional operator ( condition ? consequence : alternative ) is often referred to as both the “ternary operator” and the “tertiary operator”. What’s the difference? “Ternary” means “having three parts”. Operators in C# can be unary, binary or ternary – they take one, two or three operands. “Tertiary” means “third in order”. Compiler flaws noted in bug reports can be of primary, secondary or tertiary importance. Colours can be primary (yellow), secondary (orange) or tertiary (yello ...
by Eric Lippert via Fabulous Adventures In Coding on 2/11/2010 2:59:00 PM
UPDATE: I interrupt this episode of FAIC with a request from my friend and colleague Lucian, from the VB team, who wonders whether it is common in C# to take advantage of the fact that assignment expressions are expressions. The most common usage of this pattern is the subject of this blog entry: the fact that "chained" assignment works at all is a consequence of the fact that assignments are expressions, not statements. There are other uses too; one coul ...
by Eric Lippert via Fabulous Adventures In Coding on 2/8/2010 2:58:00 PM
As I mentioned a while back, there are some bugs in the compiler code which analyzes whether a set of classes violates the “no cycles” rules for base classes. (That is, a class is not allowed to inherit from itself, directly or indirectly, and not allowed to inherit from one of its own nested classes, directly or indirectly.) The bugs are almost all of the form where we accidentally detect a cycle in suspicious-looking generic code but in fact there is no cycle; the bugs are the result of an at ...
by Eric Lippert via Fabulous Adventures In Coding on 2/1/2010 4:29:00 PM
Which is better style? bool abc;if (Foo()) abc = Bar();else abc = false; vs bool abc = Foo() && Bar(); ? To me, this comes down to the question “is Bar useful solely for obtaining its value, or also for its side effects?” The stylistic choices should typically be driven by a desire to clearly communicate the semantics of the program fragment. The metasyntatic names are therefore making this harder to answer, not easier. Suppose the choice were in fact between: bool loginSucc ...
by Eric Lippert via Fabulous Adventures In Coding on 1/28/2010 3:10:00 PM
C# lets you call another constructor from a given constructor, but only before the body of the calling constructor runs: public C(int x) : this(x, null){ // …}public C(int x, string y){ // …} Why can you call another constructor at the beginning of a constructor block, but not at the end of the block, or in the middle of the block? Well, let's break it down into two cases. (1) You're calling a "base" constructor, and (2) you're calling a "this" constructor. For the "base" scenar ...
by Eric Lippert via Fabulous Adventures In Coding on 1/25/2010 3:00:00 PM
As I’ve discussed before, we try to reserve warnings for only those situations where we can say with almost certainty that the code is broken, misleading or useless. One reason for trying to ensure that warnings are not “false positives” is that we don’t ever want to encourage someone to take working, correct code and break it so as to remove the warning. Another is that since many people compile with “warnings are errors” turned on, we do not want to introduce a whole lot of unnecessary build ...
by Eric Lippert via Fabulous Adventures In Coding on 1/21/2010 2:20:00 PM
Today, another dialogue, and another episode of my ongoing series "what's the difference?" What’s the difference, if any, between a “destructor” and a “finalizer”? Both are mechanisms for cleaning up a resource when it is no longer in use. When I was asked this, at first I didn’t think there was a difference. But some Wikipedia searches turned up a difference; the term “destructor” is typically used to mean a deterministically-invoked cleanup, whereas a “finalizer” runs when the garbage collect ...
by Eric Lippert via Fabulous Adventures In Coding on 1/18/2010 2:28:00 PM
UPDATE: I have discovered that this issue is considerably weirder than the initial bug report led me to believe. I've rewritten the examples in this article; the previous ones did not actually demonstrate the bug. Consider the following code: struct S { private string blah; public S(string blah) { this.blah = blah; } public void Frob() { // whatever }} This method body code fragment is legal (though pro ...
by Eric Lippert via Fabulous Adventures In Coding on 1/14/2010 2:42:00 PM
Reader Jesse McGrew asks an excellent follow-up question to my 2005 post about why you cannot access a protected member from a derived class. (You probably want to re-read that post in order to make sense of this one.) I want to be clear in my terminology, so I’m going to define some terms. Suppose we have a call foo.Bar() inside class C. The value of foo is the “receiver” of the call. The compile-time type of foo is the “compile time type of the receiver”. The “runtime type of the receiver” co ...
by Eric Lippert via Fabulous Adventures In Coding on 1/11/2010 2:54:00 PM
When you have a nested loop, sometimes you want to “continue” the outer loop, not the inner loop. For example, here we have a sequence of criteria and a sequence of items, and we wish to determine if there is any item which matches every criterion: match = null;foreach(var item in items){ foreach(var criterion in criteria) { if (!criterion.IsMetBy(item)) { // No point in checking anything further; this is not &nb ...
by Eric Lippert via Fabulous Adventures In Coding on 1/7/2010 3:02:00 PM
Well, enough chit-chat, back to programming language design. Suppose you’re building electronic piano software. As we’ve discussed before, the “equal temperament” tuning for a piano goes like this: the 49th note from the left on a standard 88 key piano is A, and its frequency is 440 Hz. Each octave above or below that doubles or halves the frequency. Why? Because humans perceive the ratio between two frequencies as the relevant factor, not the (subtractive) difference. There are twelve semitone ...
by Eric Lippert via Fabulous Adventures In Coding on 12/26/2009 4:01:00 PM
Here's a little holiday cheer for you all. Or, at least for you all in Commonwealth countries. static object M<T>(T t) where T : struct{ return t;} int ii = 10;int? jj = 20;object xx = ii;object yy = jj;System.ValueType zz = ii;IComparable aa = ii;System.Enum bb = MidpointRounding.ToEven;object cc = M(ii); I hope you're having a festive holiday season. Happy Boxing Day, and we'll see you in the New Year for more fabulous adventures! [Eric is on vacation; this posting is pre-rec ...
by Eric Lippert via Fabulous Adventures In Coding on 12/10/2009 5:31:00 PM
What happens here? class Animal { } class Mammal : Animal { } class Giraffe : Mammal { }class Reptile : Animal { } …static void Foo<T>(T t) where T : Reptile { }static void Foo(Animal animal) { }static void Main() { Foo(new Giraffe()); } Most people assume that overload resolution will choose the second overload. In fact, this program produces a compile error saying that T cannot be Giraffe. Is this a compiler bug? No, this behaviour is correct according to the spec. F ...
by Eric Lippert via Fabulous Adventures In Coding on 12/7/2009 2:20:00 PM
As you probably know, there are two ways to write a LINQ query in C#. The way I personally prefer is to use the “query comprehension” syntax: from customer in customerListwhere customer.City == "London" select customer.Name Or you can, equivalently, use the “fluent method call” syntax: customerList.Where(customer=>customer.City == "London").Select(customer=>customer.Name) These are guaranteed to be equivalent because the compiler simply transforms the former syntax into the latter syntax ...
by Eric Lippert via Fabulous Adventures In Coding on 12/3/2009 2:32:00 PM
I thought it might be interesting for you all to get a precise description of how exactly it is that we determine when it is legal to put "in" and "out" on a type parameter declaration in C# 4. I'm doing this here because (1) it's of general interest, and (2) our attempt to make a more human-readable version of this algorithm in the draft C# 4.0 specification accidentally introduced some subtle errors. We're working on correcting those errors for the final release of the specification; until th ...
by Eric Lippert via Fabulous Adventures In Coding on 11/30/2009 2:51:00 PM
I've written a lot about this already, but I think one particular point bears repeating. As we're getting closer to shipping C# 4.0, I'm seeing a lot of documents, blogs, and so on, attempting to explain what "covariant" means. This is a tricky word to define in a way that is actually meaningful to people who haven't already got degrees in category theory, but it can be done. And I think it's important to avoid defining a word to mean something other than its actual meaning. A number of those d ...
by Eric Lippert via Fabulous Adventures In Coding on 11/23/2009 3:01:00 PM
Upon submitting that specification for review, even before seeing my code, Chris found a bug and an omission. The omission is that I neglected to say what happens when the ref variable is an index into a fixed-size array buffer. As it turns out, that case is also rewritten as a pointer dereference by the time we get to this point in the code, so missing that case turned out to not be a big deal. The bug is that this line is wrong: if x is ref/out instance.field then add var temp=instanc ...
by Eric Lippert via Fabulous Adventures In Coding on 11/16/2009 4:18:00 PM
Thanks to everyone who left thoughtful and insightful comments on last week's post. More countries really ought to implement Instant Runoff Voting; it would certainly appeal to the geek crowd. Many people left complex opinions of the form "I'd prefer to make the change, but if you can't do that then make it a warning". Or "don't make the change, do make it a warning", and so on. But what I can deduce from reading the comments is that there is a general lack of consensus on what the ri ...
by Eric Lippert via Fabulous Adventures In Coding on 11/12/2009 2:50:00 PM
I don't know why I haven't blogged about this one before; this is the single most common incorrect bug report we get. That is, someone thinks they have found a bug in the compiler, but in fact the compiler is correct and their code is wrong. That's a terrible situation for everyone; we very much wish to design a language which does not have "gotcha" features like this. But I'm getting ahead of myself. What's the output of this fragment? var values = new List<int>() { 100, 110, ...
by Eric Lippert via Fabulous Adventures In Coding on 11/9/2009 3:01:00 PM
Three baseball umpires are having lunch together. The first umpire says "Well, a lot of them are balls, and a lot of them are strikes, but I always calls 'em as I sees 'em." The second umpire says "Hmph. I calls 'em as they are." The third umpire slowly looks at his two colleagues and declares "They ain't nothin' until I calls 'em." Those of you unfamiliar with the bizarre rules of baseball might need a brief primer. Suppose the pitcher throws a pitch and the batter swings and misses. Such a ...
by Eric Lippert via Fabulous Adventures In Coding on 11/5/2009 2:52:00 PM
I've returned from a brief vacation, visiting friends on the island of Maui. I'd never been to that part of the world before. Turns out, it's a small island in the middle of the Pacific Ocean, entirely made out of volcanoes. Weird! But delightful. The most impressive thing about the Hawaiian Islands for me was just how obvious were -- even to my completely untrained eyes -- the geomechanical and fluvial processes which shaped the landscape. The mountains and crater ...
by Eric Lippert via Fabulous Adventures In Coding on 11/2/2009 2:23:00 PM
C# has many rules that are designed to prevent some common sources of bugs and encourage good programming practices. So many, in fact, that it is often quite confusing to sort out exactly which rule has been violated. I thought I might spend some time talking about what the different rules are. We'll finish up with a puzzle. To begin with, it will be vital to understand the difference between scope and declaration space. To refresh your memory of my earlier article: the scope of an entity is th ...
by Eric Lippert via Fabulous Adventures In Coding on 10/29/2009 1:54:00 PM
Here's a statement I read the other day about making comparisons between objects of reference type in C#: Object.ReferenceEquals(x,y) returns true if and only if x and y refer to the same object. True or false? My wife Leah recently acquired a Honda Fit, thanks to the imminant failure of the automatic transmission solenoids in her aged Honda Civic. The back seats in the Fit fold down flat. You can fit a llama or a whole pile of hula hoops or whatever into that thing. It's quite handy. Not what ...
by Eric Lippert via Fabulous Adventures In Coding on 10/15/2009 1:25:00 PM
User: Recently I found out about a peculiar behaviour concerning division by zero in floating point numbers in C#. It does not throw an exception, as with integer division, but rather returns an "infinity". Why is that? Eric: As I've often said, "why" questions are difficult for me to answer. My first attempt at an answer to a "why" question is usually "because that's what the specification says to do"; this time is no different. The C# specification says to do that in section 4.1.6. ...
by Eric Lippert via Fabulous Adventures In Coding on 10/12/2009 1:51:00 PM
Today, two more subtly incorrect myths about C#. As you probably know, C# requires all local variables to be explicitly assigned before they are read, but assumes that all class instance field variables are initially assigned to default values. An explanation of why that is that I sometimes hear is "the compiler can easily prove that a local variable is not assigned, but it is much harder to prove that an instance field is not assigned. And since the class's default constructor automatical ...
by Eric Lippert via Fabulous Adventures In Coding on 10/8/2009 4:36:00 PM
Most people will tell you that the difference between "(Alpha) bravo" and "bravo as Alpha" is that the former throws an exception if the conversion fails, whereas the latter returns null. Though this is correct, and this is the most obvious difference, it's not the only difference. There are pitfalls to watch out for here. First off, since the result of the "as" operator can be null, the resulting type has to be one that takes a null value: either a reference type or a nullable value type. You ...
by Eric Lippert via Fabulous Adventures In Coding on 10/5/2009 4:29:00 PM
I'm frequently asked "you guys added extension methods to C# 3, so why not add extension properties as well?" Good question. First, let me talk a bit about C# 3. Clearly the big feature in C# 3 was LINQ. In a sense we had only three features in C# 3: everything necessary for LINQ -- implicitly typed locals, anonymous types, lambda expressions, extension methods, object and collection initializers, query comprehensions, expression trees, improved method type inference partial methods auto ...
by Eric Lippert via Fabulous Adventures In Coding on 10/1/2009 7:53:00 PM
Another good question from StackOverflow. Why is there an implicit conversion from char to ushort, but only an explicit conversion from ushort to char? Why did the designers of the language believe that these asymmetrical rules were sensible rules to add to the language? Well, first off, the obvious things which would prevent either conversion from being implicit do not apply. A char is implemented as an unsigned 16 bit integer that represents a character in a UTF-16 encoding, so it can be conv ...
by Eric Lippert via Fabulous Adventures In Coding on 9/28/2009 4:23:00 PM
Here's a curious program fragment: object obj = "Int32";string str1 = "Int32";string str2 = typeof(int).Name;Console.WriteLine(obj == str1); // trueConsole.WriteLine(str1 == str2); // trueConsole.WriteLine(obj == str2); // false !? Surely if A equals B, and B equals C, then A equals C; that's the transitive property of equality. It appears to have been thoroughly violated here. Well, first off, though the transitive property is desirable, this is just one of many situations in which equality is ...
by Eric Lippert via Fabulous Adventures In Coding on 9/24/2009 4:53:00 PM
Another interesting question from StackOverflow: uint[] foo = new uint[10];object bar = foo;Console.WriteLine("{0} {1} {2} {3}", foo is uint[], // True foo is int[], // False bar is uint[], // True bar is int[]); // TrueWhat the heck is going on here? This program fragment illustrates an interesting and unfortunate inconsistency between the CLI type system and the C# type system. The CLI has the co ...
by via Fabulous Adventures In Coding on 9/21/2009 4:36:00 PM
Here's a good question from StackOverflow: If you have a method that takes an "X" then you have to pass an expression of type X or something convertible to X. Say, an expression of a type derived from X. But if you have a method that takes a "ref X", you have to pass a ref to a variable of type X, period. Why is that? Why not allow the type to vary, as we do with non-ref calls? Let's suppose you have classes Animal, Mammal, Reptile, Giraffe, Turtle and Tiger, with the obvious subclassing relati ...
by Eric Lippert via Fabulous Adventures In Coding on 9/14/2009 6:16:00 PM
Like "fixed" and "into", "partial" is also used in two confusingly similar-yet-different ways in C#. The purpose of a partial class is to allow you to textually break up a class declaration into multiple parts, usually parts found in separate files. The motivation for this feature was machine-generated code that is to be extended by the user by adding to it directly. When you draw a form in the forms designer, the designer generates a class for you representing that form. You can then further ...
by via Fabulous Adventures In Coding on 9/10/2009 5:12:00 PM
User: Why does this program not compile correctly in the release build? class Program { #if DEBUG static int testCounter = 0; #endif static void Main(string[] args) { SomeTestMethod(testCounter++); } [Conditional("DEBUG")] static void SomeTestMethod(int t) { } } Eric: This fails to compile in the retail build because testCounter ...
by Eric Lippert via Fabulous Adventures In Coding on 8/31/2009 4:30:00 PM
The keyword "into" in a query comprehension means two different things, depending on whether it follows a join or select/group. If it follows a join, it turns a join into a group join. If it follows a select or group then it introduces a query continuation. These two features are quite different, but easily confused. First, the group join. Suppose you've got a key -- a customer id number -- that is used as the primary key of a collection of customers, and as a foreign key of a collection of cre ...
by Eric Lippert via Fabulous Adventures In Coding on 8/27/2009 4:43:00 PM
I got an email the other day that began: I have a question about fixed sized buffers in C#: unsafe struct FixedBuffer { public fixed int buffer[100]; } Now by declaring buffer as fixed it is not movable... And my heart sank. This is one of those deeply unfortunate times when subtle choices made in the details of language design encourage misunderstandings. When doing pointer arithmetic in unsafe code on a managed object, you need to make sure that the garbage collector does not move ...
by Eric Lippert via Fabulous Adventures In Coding on 8/24/2009 4:23:00 PM
This annotation to a comment in part five I think deserves to be promoted to a post of its own. Why do we disallow anonymous iterators? I would love to have anonymous iterator blocks. I want to say something like: IEnumerable<int> twoints = ()=>{ yield return x; yield return x*10; }; foreach(int i in twoints) ... It would be totally awesome to be able to build yourself a little sequence generator in-place that closed over local variables. The reason why not is straightforward: ...
by Eric Lippert via Fabulous Adventures In Coding on 8/17/2009 2:25:00 PM
Most people understand that there’s a difference between a “rectangular” and a “ragged” two-dimensional array. int[,] rectangle = { {10, 20}, {30, 40}, {50, 60} };int[][] ragged = { new[] {10}, new[] {20, 30}, new[] {40, 50, 60} }; Here we have a two-dimensional array with six elements, arranged in three rows of two elements each. And we have a one-dimensional array with three elements, where each element is itself a one-dimensional array with one, two ...
by Eric Lippert via Fabulous Adventures In Coding on 8/13/2009 1:33:00 PM
The C# switch statement is a bit weird. Today, four quick takes on things you probably didn't know about the switch statement. Case 1: You probably know that it is illegal to "fall through" from one switch section to another: switch(attitude){ case Attitude.HighAndMighty: Console.WriteLine("High"); // we want to fall through, but this is an error case Attitude.JustMighty: Console.WriteLine("Mighty"); break;} Bu ...
by Eric Lippert via Fabulous Adventures In Coding on 8/6/2009 1:45:00 PM
I hear a lot of myths about C#. Usually the myths have some germ of truth to them, like "value types are always allocated on the stack". If you replace "always" with "sometimes", then the incorrect mythical statement becomes correct. One I hear quite frequently is "in C# every type derives from object". Not true! First off, no pointer types derive from object, nor are any of them convertible to object. Unsafe pointer types are explicitly outside of the normal type rules for the language. (If y ...
by Eric Lippert via Fabulous Adventures In Coding on 8/3/2009 2:08:00 PM
"Scope" has got to be one of the most confusing words in all of programming language design. People seem to use it casually to mean whatever is convenient at the time; I most often see it confused with lifetime and declaration space. As in "the memory will be released when the variable goes out of scope". In an informal setting, of course it is perfectly acceptable to use "scope" to mean whatever you want, so long as the meaning is clearly communicated to the audience. In a more formal setting, ...
by Eric Lippert via Fabulous Adventures In Coding on 7/30/2009 1:58:00 PM
Because I'm a geek, I enjoy learning about the sometimes-subtle differences between easily-confused things. For example: I'm still not super-clear in my head on the differences between a hub, router and switch and how it relates to the gnomes that live inside of each. Hunks of minerals found in nature are rocks; as soon as you put them in a garden or build a bridge out of them, suddenly they become stones. When a pig hits 120 pounds, it's a hog. I thought I might do an occasional series o ...
by Eric Lippert via Fabulous Adventures In Coding on 7/27/2009 2:07:00 PM
There are three good reasons to disallow unsafe blocks inside an iterator block. First, it is an incredibly unlikely scenario. The purpose of iterator blocks is to make it easy to write an iterator that walks over some abstract data type. This is highly likely to be fully managed code; it's simply not a by-design scenario. Second, the scenario is a violent mixing of "levels." You think of the level of abstraction of a programming language feature as how "far from the machine" the fea ...
by Eric Lippert via Fabulous Adventures In Coding on 7/23/2009 2:05:00 PM
A while back I posted some commentary I did for the Scripting Summer Games where I noted that there is an isomorphism between "pull" sequences and "push" events. Normally you think of events as something that "calls you", pushing the event arguments at you. And normally you think of a sequence as something that you "pull from", asking it for the next value until you're done. But you can treat a stream of event firings as being a sequence of event argument objects. And similarly, you could imple ...
by Eric Lippert via Fabulous Adventures In Coding on 7/20/2009 1:44:00 PM
Now that you know why we disallow yielding in a finally, it’s pretty straightforward to see why we also disallow yielding in a catch. First off, we still have the problem that it is illegal to “goto” into the middle of the handler of a try-protected region. The only way to enter a catch block is via the “non-local goto” that is catching an exception. So once you yielded out of the catch block, the next time MoveNext was called, we’d have no way to get back into the catch block where we left of ...
by Eric Lippert via Fabulous Adventures In Coding on 7/16/2009 1:18:00 PM
There are three scenarios in which code could be executing in a finally in an iterator block. In none of them is it a good idea to yield a value from inside the finally, so this is illegal across the board. The three scenarios are (1) normal cleanup, (2) exception cleanup, and (3) iterator disposal. For the first scenario, suppose we have something like try{ Setup(); yield return M();}finally{ yield return N(); Cleanup();} How should we transform this into an iterator st ...
by Eric Lippert via Fabulous Adventures In Coding on 7/13/2009 1:35:00 PM
A long and detailed discussion of how exactly we implement iterator blocks would take me quite a while, and would duplicate work that has been done well by others already. I encourage you to start with Raymond’s series, which is a pretty gentle introduction: part 1, part 2, part 3. If you want a more detailed look at how this particular sausage is made, Jon’s article is quite in-depth. To make a long story short, we implement iterators by: Spitting a class that implements the relevant interfac ...
by Eric Lippert via Fabulous Adventures In Coding on 7/6/2009 1:29:00 PM
Pop quiz: What does the following code do when compiled and run? class C{ public static void M(string x) { System.Console.WriteLine("static M(string)"); } public void M(object s) { System.Console.WriteLine("M(object)"); } }class Program{ static void Main() { & ...
by Eric Lippert via Fabulous Adventures In Coding on 6/29/2009 2:30:00 PM
[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, then the conversion is allowed to be covariant. That is, you can say: Giraffe GetGiraffe() { … }…Func<Animal> f = GetGiraffe; This works logically because anyone who calls f must be able to handle any animal that comes back. The actu ...
by Eric Lippert via Fabulous Adventures In Coding on 6/25/2009 1:51:00 PM
A recent comment asked why Haskell programmers sometimes write C# lambdas in this style: Func<int, Func<int, int>> add = x=>y=>x+y; which is then invoked as sum = add(2)(3); because of course the first invocation returns a function that adds two, which is then invoked with three. Why do that instead of the more straightforward Func<int, int, int> add = (x,y)=>x+y; and invoke it as sum = add(2,3); ??? I was going to write a short article on that when I remembered tha ...
by Eric Lippert via Fabulous Adventures In Coding on 6/24/2009 3:07:00 PM
My recent post about the possibility of considering maybe someday perhaps adding "top level" methods to C# in order to better enable "scripty" scenarios generated a surprising amount of immediate emphatic pushback. Check out the comments to see what I mean. Two things immediately come to mind. First off, the suggestion made by a significant number of the commenters is "instead of allowing top-level methods, strengthen the using directive." That is, if you said "using System.Math;" then all the ...
by Eric Lippert via Fabulous Adventures In Coding on 6/22/2009 3:39:00 PM
C# requires that every method be in some class, even if it is a static method in a static class in the global namespace. Other languages allow "top level" functions. A recent stackoverflow post asks why that is. I am asked "why doesn't C# implement feature X?" all the time. The answer is always the same: because no one ever designed, specified, implemented, tested, documented and shipped that feature. All six of those things are necessary to make a feature happen. All of them cost huge amounts ...
by Eric Lippert via Fabulous Adventures In Coding on 6/18/2009 1:32:00 PM
In C# you can "lift", "raise" and "hoist", and they all mean different things. To "lift" an operator is to take an operator that operates on non-nullable value types, and create from it a similar operator that operates on nullable value types. (We are a little bit inconsistent in exactly how we use the word "lifted", which I documented here.) For example, if you have public static Complex operator +(Complex x, Complex y) { ... } then we automatically generate a lifted operator for ...
by Eric Lippert via Fabulous Adventures In Coding on 6/11/2009 1:57:00 PM
I was asked recently exactly what optimizations the C# compiler performs when you specify the optimize switch. Before I answer that, I want to make sure that something is perfectly clear. The compiler’s “usage” string is not lying when it says: /debug[+|-] Emit debugging information/optimize[+|-] Enable optimizations Emitting debug information and optimizing the generated IL are orthogonal; they have no effect on each other at all (*). The usual thing to do is to ...
by Eric Lippert via Fabulous Adventures In Coding on 6/1/2009 1:48:00 PM
Fixing bugs is hard. For the purposes of this posting, I’m talking about those really “crisp” bugs -- those flaws which are entirely due to a failure on the developer’s part to correctly implement some mechanistic calculation or ensure some postcondition is met. I’m not talking about oops, we just found out that the product name sounds like a rude word in Urdu, or the specification wasn’t quite right so we changed it or the code wasn’t adequately robust in the face of a buggy caller. I mean tho ...
by Eric Lippert via Fabulous Adventures In Coding on 5/25/2009 5:09:00 PM
The generic delegate type Func<A, R> is defined as delegate R Func<A, R>(A arg). That is, the argument type is to the left of return type in the declaration of the generic type parameters, but to the right of the return type when they are used. What’s up with that? Wouldn’t it be a lot more natural to define it as delegate R Func<R, A>(A arg), so that the R’s and A’s go together? Maybe in C# it would, but in this case, it’s C# that’s the crazy one. When we speak it in English ...
by Eric Lippert via Fabulous Adventures In Coding on 5/21/2009 2:54:00 PM
User: The typeof(T) operator in C# essentially means “compiler, generate some code that gives me an object at runtime which represents the type you associate with the name T”. It would be nice to have similar operators that could take names of, say, methods and give you other metadata objects, like method infos, property infos, and so on. This would be a more pleasant syntax than passing ugly strings and types and binding flags to various Reflection APIs to get that information. Eric: I agree, ...
by Eric Lippert via Fabulous Adventures In Coding on 5/18/2009 2:13:00 PM
A number of people have asked me why there is no Microsoft-provided “ForEach” sequence operator extension method. The List class has such a method already of course, but there’s no reason why such a method could not be created as an extension method for all sequences. It’s practically a one-liner: public static void ForEach<T>(this IEnumerable<T> sequence, Action<T> action){ // argument null checking omitted foreach(T item in sequence) action(item);} My usual response to ...
by Eric Lippert via Fabulous Adventures In Coding on 5/14/2009 2:47:00 PM
Back when I started this blog in 2003, one of the first topics I posted on was the difference between Null, Empty and Nothing in VBScript. An excerpt: Suppose you have a database of sales reports, and you ask the database "what was the total of all sales in August?" but one of the sales staff has not reported their sales for August yet. What's the correct answer? You could design the database to ignore the fact that data is missing and give the sum of the known sales, but that would be answeri ...
by Eric Lippert via Fabulous Adventures In Coding on 5/11/2009 3:07:00 PM
Many programming languages, C# included, treat certain sequences of letters as “special”. Some sequences are so special that they cannot be used as identifiers. Let’s call those the “reserved keywords” and the remaining special sequences we’ll call the “contextual keywords”. They are “contextual” because the character sequence might one meaning in a context where the keyword is expected and another in a context where an identifier is expected.* The C# specification defines the following reserv ...
by Eric Lippert via Fabulous Adventures In Coding on 5/7/2009 2:19:00 PM
Suppose you’ve got a sequence of Foos and you want to project from that a sequences of Bars. That’s straightforward using LINQ: IEnumerable<Bars> bars = from foo in foos select MakeBar(foo); or, without the query sugar: IEnumerable<Bars> bars = foos.Select(foo=>MakeBar(foo)); But what if you have two sequences that you want to project from? Say you’ve got two sequences of doubles that are the same length, and you want to project a sequences of points. The operation of “project fr ...
by Eric Lippert via Fabulous Adventures In Coding on 4/9/2009 3:50:00 PM
Here’s an interesting question I got the other day: If you have an overloaded operator == then any call to the operator method is “early bound” at compile time according to the compile-time types of the operands. But calling Equals() on an object is a virtual call; the actual method called is bound at runtime according to the runtime type of the receiver. This difference seems weird to me. What’s the relevant design principle here? The short answer is that language designers and framewo ...
by Eric Lippert via Fabulous Adventures In Coding on 3/30/2009 3:10:00 PM
I wish all the questions I got were this straightforward: “I need to compare two strings for non-culture-sensitive equality. I notice that there are methods String.Equals and String.Compare which can both do that. What is the guideline on which one I should use?” I’ll answer your question, but first, a funny story (*). My buddy Steve and I were fixing the flashing that is leaking around the seal between my roof and my chimney the other day. “Steve,” I said, “hand me that screwdriver.” Steve h ...
by Eric Lippert via Fabulous Adventures In Coding on 3/19/2009 1:46:00 PM
I get a fair number of questions about the C# cast operator. The most frequent question I get is: short sss = 123;object ooo = sss; // Box the short.int iii = (int) sss; // Perfectly legal.int jjj = (int) (short) ooo; // Perfectly legalint kkk = (int) ooo; // Invalid cast exception?! Why? Why? Because a boxed T can only be unboxed to T ...
by Eric Lippert via Fabulous Adventures In Coding on 3/10/2009 4:42:00 PM
Here's an interesting question I got the other day: We are writing code to translate old mainframe business report generation code written in a BASIC-like language to C#. The original language allows "goto" branching from outside of a loop to the interior of a loop, but C# only allows branching the other way, from the interior to the exterior. How can we branch to the inside of a loop in C#? I can think of a number of ways to do that. First, don't do it. Write your translator so that it detect ...
by Eric Lippert via Fabulous Adventures In Coding on 3/6/2009 4:41:00 PM
A couple years ago I wrote a bit about how our codegen for the lock statement could sometimes lead to situations in which an unoptimized build had different potential deadlocks than an optimized build of the same source code. This is unfortunate, so we've fixed that for C# 4.0. However, all is still not rainbows, unicorns and Obama, as we'll see. Recall that lock(obj){body} was a syntactic sugar for var temp = obj;Monitor.Enter(temp);try { body }finally { Monitor.Exit(temp); } The problem here ...
by Eric Lippert via Fabulous Adventures In Coding on 2/6/2009 6:19:31 PM
As I have said before many times, there is only one sensible way to make a performant application. (As an aside: perfectly good word, performant, deal with it!) That is: Set meaningful, measurable, customer-focused goals. Write the code to be as clear and correct as possible. Carefully measure your performance against your goals. Did you meet your goal? Great! Don't waste any time on performance analysis. Spend your valuable time on features, documentation, bug fixing, robustness, security, ...
by Eric Lippert via Fabulous Adventures In Coding on 2/4/2009 9:52:48 PM
The other day my charming wife Leah and I were playing Scrabble Brand Crossword Game (a registered trademark of Hasbro and Mattel) as is our wont. I went first, drawing the Q and a bunch of vowels. Knowing that the Q is death to hold onto, I immediately opened with QI for 22 points. I silently thanked Miriam-Webster for adding QI, KI and ZA to the OSPD 4th edition. My thankfulness was short-lived, as Leah thought for a few moments and then played ANALYST, for the fifty point "bingo" bonus, ma ...
by Eric Lippert via Fabulous Adventures In Coding on 2/2/2009 9:02:26 PM
Here is yet another question I got from a C# user recently: I have a class that represents a business rule. I want to add some rule metadata that could be used by consumers to retrieve a friendlier rule name, description, and anything else that makes sense. Should this information be exposed as an attribute or property on the class? I would say to absolutely go for a property in this case, for four reasons. First, properties are highly discoverable. Consumers of this class can use IntelliSens ...
by Eric Lippert via Fabulous Adventures In Coding on 1/28/2009 6:10:56 PM
A thing that makes a reader go hmmm is why in C#, int divided by long has a result of long, even though it is clear that when an int is divided by a (nonzero) long, the result always fits into an int. I agree that this is a bit of a head scratcher. After scratching my head for a while, two reasons to not have the proposed behaviour came to mind. First, why is it even desirable to have the result fit into an int? You'd be saving merely four bytes of memory and probably cheap stack memory at that ...
by Eric Lippert via Fabulous Adventures In Coding on 1/26/2009 5:59:00 PM
In my recent request for things that make you go hmmm, a reader notes that you cannot use "var" on fields. Boy, would I ever like that. I write this code all the time: private static readonly Dictionary<TokenKind, string> niceNames = new Dictionary<TokenKind, string>() { {TokenKind.Integer, "int"}, ... Yuck. It would be much nicer to be able to write private static readonly var niceNames = new Dictionary<TokenKind, string>()... You'd thin ...
by Eric Lippert via Fabulous Adventures In Coding on 1/14/2009 5:11:25 PM
Here's a question I got from a C# user last year, a question I get fairly frequently: User: With “regular” explicit properties, I tend to use the private backing field directly from within the class. Of course, with an automatic property, you can’t do this. My concern is that in the future, if I decide I need an explicit property for whatever reason, I’m left with the choice of changing the class implementation to use the new private field, or continue going through the property. I’m not sure ...
by Eric Lippert via Fabulous Adventures In Coding on 11/7/2008 4:18:00 PM
When we're designing a new version of the language, something we think about a lot is whether the proposed new features "hang together". Having a consistent "theme" to a release makes it easier for us to prioritize and organize proposals, it makes it easier for our marketing and user education people to effectively communicate with customers, it's just all-around goodness. If you look at C# 2.0, it was a bit of a grab-bag. The big features were clustered around the notion of enabling rich, type ...