Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit conversion with null-coalescing operator

I discovered a strange behaviour of my program and after futher analysis, I was able to find that there is probably something wrong either in my C# knowledge or somewhere else. I beleive it's my mistake but I cannot find an answer anywhere...

public class B
{
    public static implicit operator B(A values) 
    {
        return null; 
    }
}
public class A { }

public class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        B b = a ?? new B();
        //b = null ... is it wrong that I expect b to be B() ?
    }
}

The variable "b" in this code is evaluated to null. I don't get why is it null.

I googled and found a response in this question - Implicit casting of Null-Coalescing operator result - with the official specification.

But following this specification, I can't find the reason why "b" is null :( Maybe I'm reading it wrong in which case I apologize for spamming.

If A exists and is not a nullable type or a reference type, a compile-time error occurs.

...that's not the case.

If b is a dynamic expression, the result type is dynamic. At run-time, a is first evaluated. If a is not null, a is converted to dynamic, and this becomes the result. Otherwise, b is evaluated, and this becomes the result.

...that's also not the case.

Otherwise, if A exists and is a nullable type and an implicit conversion exists from b to A0, the result type is A0. At run-time, a is first evaluated. If a is not null, a is unwrapped to type A0, and this becomes the result. Otherwise, b is evaluated and converted to type A0, and this becomes the result.

...A exists, implicit conversion from b to A0 does not exist.

Otherwise, if A exists and an implicit conversion exists from b to A, the result type is A. At run-time, a is first evaluated. If a is not null, a becomes the result. Otherwise, b is evaluated and converted to type A, and this becomes the result.

...A exists, implicit conversion from b to A does not exist.

Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B. At run-time, a is first evaluated. If a is not null, a is unwrapped to type A0 (if A exists and is nullable) and converted to type B, and this becomes the result. Otherwise, b is evaluated and becomes the result.

...b has a type B and implicit conversion exists from a to B. a is evaluated into null. Therefore, b should be evaluated and b should be the result.

Otherwise, a and b are incompatible, and a compile-time error occurs. Does not happen

Am I missing something please?

like image 497
Mirek Avatar asked Jan 27 '14 17:01

Mirek


1 Answers

Why did you expect the null-coalescing operator to return new B()? a is not null, so a ?? new B() evaluates to a.

Now that we know that a will be returned, we need to determine the type of the result (T) and whether we need to cast a to T.

• Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B. At run-time, a is first evaluated. If a is not null, a is unwrapped to type A0 (if A exists and is nullable) and converted to type B, and this becomes the result. Otherwise, b is evaluated and becomes the result.

An implicit conversion exists from A to B, so B is the result type of the expression. Which means a will be implicitly casted to B. And your implicit operator returns null.

In fact, if you write var b = a ?? new B(); (notice the var), you'll see that the compiler infers B to be the type returned by the expression.

like image 87
dcastro Avatar answered Sep 22 '22 03:09

dcastro