Null-coalescing and right-associative in C # - clarification?
I saw a twitter about null-coalescing
(which is the correct associative one):
From SPEC:
For example, a shape expression
a ?? b ?? c
evaluates toa ?? (b ?? c)
So, another guy came along who answered that it can be tested and verified with an example:
void Main()
{
Console.WriteLine ((P)null ?? (string)null ?? "b555");
}
public class P
{
public static implicit operator P(string b) {throw new Exception(b??"a");}
}
Result:
Exception: b555
But I didn't understand the behavior.
Question
I already know which ??
is of very low priority, but still:
(P)null
must evaluate first (higher priority)!
But it seems that
a ?? (b ?? c)
Evaluated first.
Why?
In other words, it seems that these are events:
(P)(null ?? ((string)null ?? "b555"))
And then:
(P)(null ?? "b555")
And then:
(P)"b555"
But I don't understand why it (P)
is applied to the whole coalesce expression and not to null
(in (P)null
)
source to share
Why should your implicit conversion be applied to null
to (P)null
? (P)null
gives a null reference statically typed on P
, why use any conversion from string here? In (P)null
no mention of one line.
Notice how the compiler statically injects the following expressions:
((string)null ?? "b555") -> string
((P)null ?? ...some expression of type string...) -> P
Thus,
((P)null ?? (string)null ?? "b555") -> P
The expression can now be solved like this:
-
(P)null
is null, so we're looking at the right side. -
((string)null ?? "b555")
outputs a string"b555"
(does not participate in P). -
((P)null ?? "b555")
results in a value"b555"
. Since the static type((P)null ?? "b555")
is equalP
, it isb555
implicitly converted toP
, causing the implicit conversion. -
We are getting the "b555" exception as expected.
PS: If anyone is interested in a more detailed explanation in the form of a dialogue, we took this topic in the chat, and here is the transcript .
ยน Proof:
public static void Main()
{
var x = ((P)null ?? "abc");
x.A(); // compiles
}
public class P
{
public static implicit operator P(string b) {throw new Exception(b??"a");}
public void A() {}
}
source to share