Here’s a question I’m asked occasionally:
void M<T>(T t) where T : Animal
// This gives a compile-time error:
if (t is Dog)
// But this does not:
if (t is Dog)
(t as Dog).Bark();
What’s going on here? Why is the cast operator rejected? The reason illustrates yet again that the cast operator is super weird.
One of the C# oddities I noted in my recent article was that I find it odd that creating a numeric type with less-than, greater-than, and similar operators requires implementing a lot of redundant methods, methods whose values could be deduced by simply implementing a comparator. For an example of such, see my previous series of articles on implementing math from scratch.
A number of people commented that my scheme does not work in a world with nullable arithmetic (or, similarly, NaN semantics, which are similar enough that I’m not going to call out the subtle differences here.) That reminded me that I’d been intending for some time to point out that when it comes to comparison operators, nullable arithmetic is deeply weird. Check out this little program: Continue reading
Hey everyone, I am finally back from my many travels this summer and looking forward to doing some blogging this autumn. I’ll post some vacation photos when I have them sorted out. Until then, here’s an article that the nice people at InformIT asked me to write: what are my ten least favourite C# features?
I’m sure I missed some of your least favourites; I’d love to know what your pet peeves are in the comments here or on the article itself.
I briefly discussed copy-paste errors in code earlier; though this is a rich area of defects that I will probably at some point go into more detail on, that’s not for today.
Though this is a trivial little issue, I think it is worthwhile to illustrate how to think about these sorts of defects.
What is the defect?
Last week Jon Skeet “tweeted” humorously that in his work on the ECMA committee that is standardizing C#, they had found a mistake in the specification that was probably my fault; some commenters suggested that perhaps hell had also frozen over.
This is a sequel to my 2009 post about division of long integers.
I am occasionally asked why this code produces a bizarre error message:
Console.WriteLine(Math.Round(i / 6000000000, 5));
i is an integer.
The error is:
The call is ambiguous between the following methods:
'System.Math.Round(double, int)' and 'System.Math.Round(decimal, int)'
Um, what the heck? Continue reading
One of the nice things about a project as large as the Roslyn project is that you have an opportunity to really think hard about your past mistakes and hopefully fix them. When I was working on getting these error messages reported in Roslyn I realized that trying to match exactly the behavior of the original compiler would be actively making the world a worse place, so I took a big step back and started sending a lot of emails to Mads, Neal, Anthony and the rest of the Roslyn gang to try and get a better design worked out. All the godawful nonsense I told you about in the previous two episodes will be fixed in Roslyn.
Last time I gave you the challenge to find a case where the same simple name means two different things, without introducing a new local/parameter/range variable into scope, that produces an error. It seems like it ought to be impossible; if nothing new has been introduced to a local scope then how can name resolution choose two different things? The relevant section of the C# specification (220.127.116.11 Invariant meaning in blocks) only gives the example I gave last time, of a local having the same name as a field.
The key to solving the riddle is a little-known rule about resolving a name from a set of possible class members: Continue reading