Since true
is not a string type, how is null + true
a string ?
string s = true; //Cannot implicitly convert type 'bool' to 'string' bool b = null + true; //Cannot implicitly convert type 'string' to 'bool'
What is the reason behind this?
An empty string is a string instance of zero length, whereas a null string has no value at all. An empty string is represented as "" . It is a character sequence of zero characters. A null string is represented by null .
A string will be null if it has not been assigned a value. A string will be empty if it is assigned “” or String.
To check for a truthy value: if (strValue) { // strValue was non-empty string, true, 42, Infinity, [], ... } To check for a falsy value: if (!strValue) { // strValue was empty string, false, 0, null, undefined, ... }
Bizarre as this may seem, it's simply following the rules from the C# language spec.
From section 7.3.4:
An operation of the form x op y, where op is an overloadable binary operator, x is an expression of type X, and y is an expression of type Y, is processed as follows:
- The set of candidate user-defined operators provided by X and Y for the operation operator op(x, y) is determined. The set consists of the union of the candidate operators provided by X and the candidate operators provided by Y, each determined using the rules of §7.3.5. If X and Y are the same type, or if X and Y are derived from a common base type, then shared candidate operators only occur in the combined set once.
- If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Otherwise, the predefined binary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. The predefined implementations of a given operator are specified in the description of the operator (§7.8 through §7.12).
- The overload resolution rules of §7.5.3 are applied to the set of candidate operators to select the best operator with respect to the argument list (x, y), and this operator becomes the result of the overload resolution process. If overload resolution fails to select a single best operator, a binding-time error occurs.
So, let's walk through this in turn.
X is the null type here - or not a type at all, if you want to think of it that way. It's not providing any candidates. Y is bool
, which doesn't provide any user-defined +
operators. So the first step finds no user-defined operators.
The compiler then moves on to the second bullet point, looking through the predefined binary operator + implementations and their lifted forms. These are listing in section 7.8.4 of the spec.
If you look through those predefined operators, the only one which is applicable is string operator +(string x, object y)
. So the candidate set has a single entry. That makes the final bullet point very simple... overload resolution picks that operator, giving an overall expression type of string
.
One interesting point is that this will occur even if there are other user-defined operators available on unmentioned types. For example:
// Foo defined Foo operator+(Foo foo, bool b) Foo f = null; Foo g = f + true;
That's fine, but it's not used for a null literal, because the compiler doesn't know to look in Foo
. It only knows to consider string
because it's a predefined operator explicitly listed in the spec. (In fact, it's not an operator defined by the string type... 1) That means that this will fail to compile:
// Error: Cannot implicitly convert type 'string' to 'Foo' Foo f = null + true;
Other second-operand types will use some other operators, of course:
var x = null + 0; // x is Nullable<int> var y = null + 0L; // y is Nullable<long> var z = null + DayOfWeek.Sunday; // z is Nullable<DayOfWeek>
1 You may be wondering why there isn't a string + operator. It's a reasonable question, and I'm only guessing at the answer, but consider this expression:
string x = a + b + c + d;
If string
had no special-casing in the C# compiler, this would end up as effectively:
string tmp0 = (a + b); string tmp1 = tmp0 + c; string x = tmp1 + d;
So that's created two unnecessary intermediate strings. However, because there's special support within the compiler, it's actually able to compile the above as:
string x = string.Concat(a, b, c, d);
which can create just a single string of exactly the right length, copying all the data exactly once. Nice.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With