Site: http://blogs.msdn.com/b/ericlippert/ Link: http://blogs.msdn.com/ericlippert/rss.xml
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 ...
[ read more ]
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 ...
by Eric Lippert via Fabulous Adventures In Coding on 10/29/2008 4:48:00 PM
Amazingly enough, it has happened again. Why does this keep happening to me? Anders, Mads and Eric on C# 4.0: C# 4.0 with Anders Hejlsberg, Mads Torgersen, and Eric Lippert - Part 1 of 2 C# 4.0 with Anders Hejlsberg, Mads Torgersen, and Eric Lippert - Part 2 of 2 Anders, Mads and Scott on the new dead-trees edition of the C# 3.0 specification: The C# Programming Language, 3rd Edition Enjoy! ...
by Eric Lippert via Fabulous Adventures In Coding on 10/28/2008 3:01:00 PM
Well, I intended to spend the last three weeks blogging about C# design process in anticipation of our announcements at the PDC, and then I got crazy busy at work and never managed to do so! As I'm sure you know by now, we have announced the existence and feature set of that hitherto hypothetical language C# 4.0. Of course I'll be blogging extensively about that over the next year; today though I want to pick up where I left off last time and talk about the tragedy of Object Happiness Disease. ...
by Eric Lippert via Fabulous Adventures In Coding on 10/8/2008 3:06:00 PM
An attentive reader pointed me at this long thread on a third-party forum where some people are musing about possible future features of C#. There is far, far more here than I possibly have time to respond to in any kind of detail. Also, I am not going to spill the beans. Anders is giving a talk at the PDC at the end of the month. His talk is titled "The Future of C#" and I'm not going to steal Anders' thunder (or give our marketing department conniptions) by giving specific details a ...
by Eric Lippert via Fabulous Adventures In Coding on 9/26/2008 3:17:00 PM
In this episode of FAIC, a conversation I had with a C# user recently. Next time, some further thoughts on how to use the CLR security system in this sort of scenario. Him: I have this abstract class defined in one assembly: // Assembly FooBar.DLLpublic abstract class Foo{ internal abstract void DoSomething();// ...} I want to create a concrete class derived directly from Foo in another assembly, Blah.DLL. Me: You are going to have to learn to live with disappointment. Hi ...
by Eric Lippert via Fabulous Adventures In Coding on 9/22/2008 6:04:00 PM
I got a moral question from an author of programming language textbooks the other day requesting my opinions on whether or not beginner programmers should be taught how to use arrays. Rather than actually answer that question, I gave him a long list of my opinions about arrays, how I use arrays, how we expect arrays to be used in the future, and so on. This gets a bit long, but like Pascal, I didn't have time to make it shorter. Let me start by saying when you definitely sh ...
by Eric Lippert via Fabulous Adventures In Coding on 6/17/2008 3:20:00 PM
I want to start this by discussing the purpose of method type inference, and clearing up some potential misunderstandings about type inference errors. First off though, a brief note on nomenclature. Throughout this series when I say "type inference" I mean "method type inference", not any of the other forms of type inference we have in C# 3.0. (Implicitly typed locals, implicitly typed arrays, and so on.) The purpose of type inference is to allow generic methods to be called without explicitly ...
by Eric Lippert via Fabulous Adventures In Coding on 5/28/2008 3:16:00 PM
Back in November I wrote a bit about a corner case in method type inference which does not work as expected or as specified in C# 3.0. A number of people made blog comments, sent me mail, and entered "Connect" issues with additional problems and ideas for how we could improve this algorithm. (Particular thanks to nikov for his many fascinating and detailed Connect reports.) As a result, as soon as I had time I embarked upon a detailed review of the method type inference specification and the im ...
by Eric Lippert via Fabulous Adventures In Coding on 5/23/2008 2:19:00 PM
Raymond has written about this, I have written about Raymond writing about it, but I still frequently get questions from people who are unclear on the difference between precedence, associativity and evaluation order. I suspect that this confusion arises from the difference between how most people are trained to evaluate arithmetical expressions versus how compilers generate code to evaluate arithmetical expressions. As a child it was drilled into me that the way to evaluate an arithmetica ...
by Eric Lippert via Fabulous Adventures In Coding on 5/21/2008 2:34:00 PM
Here's some back-and-forth from an email conversation I had with a user a while back. Why should one avoid method hiding? If there were no advantages and only disadvantages then we would not have added it to the language in the first place. C# implements hiding because hiding is frequently useful. I therefore deny the premise of the question. One should not avoid method hiding if it is the right thing to do. But I find method hiding confusing. It lets derived types appear to ...
by Eric Lippert via Fabulous Adventures In Coding on 5/19/2008 2:01:00 PM
Here's a question I get fairly frequently: the user desires to create a generic type Bar<T> constrained such that T is guaranteed to be a Foo<U>, for some U. The way they usually try to write this is class Bar<T> where T : Foo<T> {... which of course then does not work. The user discovers this when they type new Bar<Foo<string>>() and get an error stating that the constraint has been violated. Which it certainly has. The constraint says that T m ...
by Eric Lippert via Fabulous Adventures In Coding on 5/14/2008 2:10:00 PM
Consider this program which attempts to mutate a readonly mutable struct. What happens? struct Mutable { private int x; public int Mutate() { this.x = this.x + 1; return this.x; }} class Test { public readonly Mutable m = new Mutable(); static void Main(string[] args) { Te ...
by Eric Lippert via Fabulous Adventures In Coding on 5/12/2008 1:57:00 PM
OK, computers aren't entirely dumb when it comes to LINQ. Here's an example of a place where we're a bit smarter. Consider the following query: IEnumerable<int> query = from n in number_array orderby n select n; Does this get transformed by the compiler into IEnumerable<int> query = number_array.OrderBy(n => n); or IEnumerable<int> query = number_array.OrderBy(n => n).Select( n => n ); ? This question caused tremendous debate amongst the members of the C# design and i ...
by Eric Lippert via Fabulous Adventures In Coding on 5/9/2008 3:20:00 PM
A few short takes today, from questions I've received recently about LINQ in C# 3.0. The first question was "in the following code, does it really check every single non-negative integer, or does it use the knowledge that once you're beyond ten, you can stop iterating?" var smallNumbers = Enumerable.Range(0, int.MaxValue).Where(n => n < 10);foreach (int i in smallNumbers) Console.WriteLine(i);The former. You asked LINQ to Objects to apply a predicate to a sequence ...
by Eric Lippert via Fabulous Adventures In Coding on 5/2/2008 4:13:50 PM
In Part Two I asked a couple of follow-up questions, the first of which was: Suppose you were a hostile third party and you wanted to mess up the parenting invariant. Clearly, if you are sufficiently trusted, you can always use private reflection or unsafe code to muck around with the state directly, so that's not a very interesting attack. Any other bright ideas come to mind for ways that this code is vulnerable to tampering? Before I get into some ideas for attacks, I want to re-emphasize t ...
by Eric Lippert via Fabulous Adventures In Coding on 4/24/2008 4:46:48 PM
Holy goodness, I've been busy. The MVP Summit was fabulous for us; thanks to all who attended and gave us great feedback on our ideas for evolving the languages and tools. And I've been doing some longer-lead thinking and working on language futures, which I will blog about at a later date. Last time I promised another oddity of "protected" semantics. An issue that I get asked about all the time involves the meaning of this code: namespace Foo { public class Base { prot ...
by Eric Lippert via Fabulous Adventures In Coding on 3/28/2008 11:30:43 PM
This is a follow-up to my 2005 post on the same subject which I believe sets a personal record for the longest time between parts of a series. (Of course, I didn't know it was a series when I started it.) Please read the previous article in this series, as this post assumes knowledge of part one. ....... OK, now that you've read that, it's clear why you can only access a protected member from an instance of an object known to be of a type at least as derived as the current context. You ca ...
by Eric Lippert via Fabulous Adventures In Coding on 2/18/2008 3:25:12 PM
As you might have figured out, the answer to last week's puzzle is "if the constructors and initializers run in their actual order then an initialized readonly field of reference type is guaranteed to be non null in any possible call. That guarantee cannot be met if the initializers run in the expected order." Suppose counterfactually that initializers ran in the expected order, that is, derived class initializers run after the base class constructor body. Consider the following pathological ca ...
by Eric Lippert via Fabulous Adventures In Coding on 2/15/2008 11:01:41 PM
Pop quiz! What do you expect the output of this program to be? using System; class Foo{ public Foo(string s) { Console.WriteLine("Foo constructor: {0}", s); } public void Bar() { }} class Base{ readonly Foo baseFoo = new Foo("Base initializer"); public Base() { Console.WriteLine ...
by Eric Lippert via Fabulous Adventures In Coding on 2/12/2008 11:40:00 PM
At long last, let's get to that double-ended queue. Sorry for leaving you in suspense! Last time we came up with a non-solution -- as commenters immediately discovered, the given algorithm and data structure are deeply inefficient. However, the basic idea is sound. There are a number of ways to solve this problem, but the way I'm going to talk about today is a much more efficient variation on the theme of our previous unsuccessful attempt. That is, have cheap access to the endpoints, and ...
by Eric Lippert via Fabulous Adventures In Coding on 1/22/2008 3:15:53 PM
Based on the comments, the implementation of a single-ended queue as two stacks was somewhat mind-blowing for a number of readers. People, you ain't seen nothing yet. Before we get into the actual bits and bytes of the solution, think for a bit about how you might implement an immutable queue which could act like both a stack or a queue at any time. You can think of a stack as "it goes on the left end, it comes off the left end", and a queue as "it goes on the left end, it comes off the right e ...
by Eric Lippert via Fabulous Adventures In Coding on 1/22/2008 12:13:12 AM
Good Monday morning all. I have received a lot of good comments on this series so far that I thought I would speak to a bit. Academic? First and foremost, a number of people have asked questions which could be summed up as "isn't this just an academic exercise? I have a job to do here!" No, I do not believe that it is just an academic exercise, not at all. When I compare the practical, solving-real-problems code I write using immutable or ("mostly" immutable objects) to that which uses highly m ...
by Eric Lippert via Fabulous Adventures In Coding on 1/18/2008 7:02:13 PM
Last year we declared a relatively simple interface to represent an immutable binary tree. We noticed that it was different from every other interface that we've declared so far, in that it really said nothing at all about the immutability of the tree. One normally thinks of immutable data types not in terms of their shape, but rather in terms of what operations may be performed on the data type. Operations are usually either to query the object somehow, or to "modify" it by producing new modif ...
by Eric Lippert via Fabulous Adventures In Coding on 12/19/2007 8:01:00 PM
Lots of good comments on my previous post. To briefly follow up: One of the downsides of immutable tree implementations is that usually the tree must be built from the leaves up, which is not always convenient. We'll look at implementations which hide this fact from the user in future posts. One smartypants pointed out that sure, this tree can have cycles -- if you have another binary tree implementation that has cycles and then paste such a cyclic tree in. True; what I meant was that using ...
by Eric Lippert via Fabulous Adventures In Coding on 12/18/2007 7:30:00 PM
OK, we've gotten pretty good at this by now. A straightforward implementation of an immutable generic binary tree requires little comment on the basics. A binary tree is either empty, or a value, left tree and right tree: public interface IBinaryTree<V>{ bool IsEmpty { get; } V Value { get; } IBinaryTree<V> Left { get; } IBinaryTree<V> Right { get; }} And our implementation has, as always, a singleton emp ...
by Eric Lippert via Fabulous Adventures In Coding on 12/10/2007 3:04:00 PM
An immutable queue is a bit trickier than an immutable stack, but we’re tough, we can handle it. First off, the interface is straightforward; enqueuing or dequeuing results in a new queue: public interface IQueue<T> : IEnumerable<T> { bool IsEmpty { get; } T Peek(); IQueue<T> Enqueue(T value); ...
by Eric Lippert via Fabulous Adventures In Coding on 12/6/2007 3:55:00 PM
Now suppose we had a hypothetical future version of C# in which interface covariance worked, and we wanted a covariant immutable stack. That is, we want to be able to implicitly convert an IStack<Giraffe> to IStack<Mammal>. As we've already discussed, this doesn't make much sense in an array, even though doing so is legal in C# today. If you cast a Giraffe[] to Mammal[] then you can try to put a Tiger into the Mammal[] and it will fail at run time. It seems like the same should be t ...
by Eric Lippert via Fabulous Adventures In Coding on 12/4/2007 3:26:00 PM
Let’s start with something simple: an immutable stack. Now, immediately I hear the objection: a stack is by its very nature something that changes. A stack is an abstract data type with the interface void Push(T t);T Pop();bool IsEmpty { get; } You push stuff onto it, you pop stuff off of it, it changes. How can it be immutable? Every time you need to make a data structure immutable, you use basically the same trick: an operation which “changes” the data structure does so by constructing a new ...
by Eric Lippert via Fabulous Adventures In Coding on 11/13/2007 5:56:00 PM
I said in an earlier post that I believe that immutable objects are the way of the future in C#. I stand by that statement while at the same time noting that it is at this point sufficiently vague as to be practically meaningless! “Immutable” means different things to different people; different kinds of immutability have different pros and cons. I’d like to spend some time over the next few weeks talking about possible directions that C# could go to improve the developer experience when writin ...
by Eric Lippert via Fabulous Adventures In Coding on 11/5/2007 6:48:00 PM
Thanks all for your excellent feedback on my variance series. I am still reading and digesting the feedback and I shall take it to the language design committee later this month. Returning to less hypothetical but equally complicated issues, today, what I thought would be a rather obscure issue with C# 3.0 type inference which multiple people have reported to me since the last beta. Perhaps it is not as obscure as I thought! Consider this (contrived, but simplified from real code) example ...
The content of the postings is owned by the respective author. CSharpFeeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on CSharpFeeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.