This is a bit off-topic, but bare with me 🙂

My good friend Yaniv just discovered something a bit wierd in C# 2005 regarding Nullable types.

Consider the following piece of code:

DateTime? modified;
modified = row.IsmodifiedNull() ?
null : row.modified;

What it basically does is sets null to “modified” if row.IsmodifiedNull() returns true or sets row.modified into “modified” if row.IsmodifiedNull() returns false.

This code cannot be compiled. The compiler yelled that it cannot set null to “modified” even though modified is defined as a Nullable type.

This code is actually equivalent to the abobe code, doesn’t use the “?” syntax and DOES compile:

if (row.IsmodifiedNull())
{
modified = null;
}
else
{
modified = row.modified;
}

After further investigation, Yaniv changed the code to the code below and it did work:

modified = row.IsmodifiedNull() ? (
Nullable<DateTime>)null : row.modified;

Its reasonable to assume that the “?” syntax is eventually translated in compile time into an “if” statement so why in a normal “if” statement setting “modified” to null works and in the “?” syntax it does not.

Bug? Feature?

I wonder who can comment on this.

  • Ayende Rahien

    This is a feature, actually, fromt he compiler stand point

    (boolean ? expression : expression) – should have the /same/ type.

    I’m assuming that row.Modified is a DateTime, if so, then what you told the compiler is something like:

    if(row.IsModidifedNull())
    {
    row.Modified = (DateTime)null;
    }

    You see the problem?

  • shouldn’t null be automatically casted to the appropriate type?

  • Barry Kelly

    ayende rahien is not quite right: it’s not necessary that both B and C have the same type. For a ternary expression ‘A ? B : C’, where A is of type bool, the result type for the whole expression is B if C can be converted into B, or C if B can be converted into C. The least costly conversion is chosen if there is a conflict. If there is no conversion possible, then there is an error. If there are multiple possible conversions of the same precedence, then there’s an ambiguity error.

    The important thing to remember is that the compiler never tries to create a third, unified, type and convert B and C to this third unified type.

    In the specific example, the B type is the null type (i.e. the type of the null constant), while the C type is a non-nullable date-time. Neither of these types can be converted into the other, so there’s a compiler error. If you cast either side to DateTime?, then it’ll work as desired.