Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a bug in Visual Studio 2010 compiler?

DateTime? date = null;
string tmp = "a" + "(" + date ?? "blablabla" + ")";

Console.WriteLine(tmp);

This will print something close to: 'a ('.

Is this a bug with null-coalescing operator? If I put date ?? "blablabla" in parenthesis, it is underlined as error.

like image 908
kul_mi Avatar asked Jul 09 '13 12:07

kul_mi


Video Answer


2 Answers

Null-coalescing operator ?? has a lower precedence than the + operator, so your code is equal to

string tmp = ("a" + "(" + date) ?? ("blablabla" + ")");

Since everything in the + operation with a string produces a string (by calling .ToString() on all non-string operands), your code will always produce the "a(" string.

like image 175
AgentFire Avatar answered Oct 02 '22 13:10

AgentFire


First, you should always assume it's your fault, not the compiler's fault; select isn't broken. Do you honestly think the Visual Studio 2010 implementation of the ?? operator hasn't been battle tested? When you encounter something that doesn't match your expectations, check your expectations. Get out the manual, and make sure that you understand exactly what is suppose to happen. In this case, open the language specification.

If you proceed to §1.4 of the specification, you'll see a table that groups operators into precedence groupings; you can also find it online. In particular, the null coalescing operator ?? is near the bottom, above only the lowly conditional ternary operator and assignments and =>. It is below the additive operator. Thus, your statement

string tmp = "a" + "(" + date ?? "blablabla" + ")";

is treated by the compiler as

string tmp = (("a" + "(" + date) ?? ("blablabla" + ")"));

I'm not going to be completely pedantic and also parenthesize the first additive expression1. Since the left-hand-side of the expression in that statement is never null, of course it always assigns "a(" (or "a(" + date.ToString() when date.HasValue is true) to tmp.

The main point is that you had an incorrect expectation as to what should be happening that you should have verified against the manual.

If I put date ?? "blablabla" in parenthesis, it is underlined as error.

Of course it is. Did you even read the error message? It probably tells you that you can't do ?? on a DateTime? and a string because there are no implicit conversions between DateTime? and string in either direction. This, too, is covered in the language specification; see §7.13. You have to read this message and respond to it. To get something semantically equivalent to what you're trying to express, you'll have to resort to the conditional ternary operator:

date.HasValue ? date.ToString() : "blablabla"

and then wrap that whole thing in parentheses because the conditional ternary operator has very low precedence.

Finally, I find a correctly parenthesized version of your code rather ugly, not fun to read, and probably not enjoyable to maintain. Just make it simple, please:

var tmp = String.Format("a({0})", 
                       date.HasValue ? date.ToString() : "blablabla");

Now it is so clear what is going on and what is going to happen. I don't have to think to understand it. Save your thinking for the difficult problems you'll encounter.

1: Be careful. We would need to add in a method call to date.ToString (which has the highest precedence) before attempting to correctly figure out what is evaluated first.

like image 37
jason Avatar answered Oct 02 '22 14:10

jason