The new ?? and ??? operators

Max Samukha samukha at voliacable.com.removethis
Tue Sep 25 04:30:30 PDT 2007


On Tue, 25 Sep 2007 11:39:51 +0300, "Rioshin an'Harthen"
<rharth75 at hotmail.com> wrote:

>"Janice Caron" <caron800 at googlemail.com> kirjoitti viestiss? 
>news:mailman.289.1190665392.16939.digitalmars-d at puremagic.com...
>> On 9/24/07, Rioshin an'Harthen <rharth75 at hotmail.com> wrote:
>>> I can't begin to count how many times I've written code like
>>>
>>>     long id = data.GetLong("ID") ?? 0;
>>
>> Please could you explain what that does, as I don't speak C# and can't
>> make any sense of it. What is the return type of GetLong()? What is
>> the type of the variable named data?
>
>Certainly. :)
>
>GetLong, as the name suggests, is used in this example to return a long 
>(signed 64-bit value) from the database column ID, with the current database 
>row referenced through the variable data (which, e.g. could be of type 
>MySqlDataReader). GetLong may, if the column (in the row accessed) doesn't 
>contain a value, return null, to signify this, since 0 (or any other value) 
>may be a legal value in the database.
>
>>>     long? id = data.GetLong("ID");
>>
>> What does the question mark after long mean? What is the type of the
>> variable named id? Is is "long" or "long?" ?
>
>The question mark after a type name means the type is nullable: basically, 
>in addition to its normal range may contain the value null. A nullable type 
>can be built using a struct or class, and as far as I'm able to tell from 
>the standard, that's how the C# compiler creates it.
>
>If you wish further information on nullable types, I'd recommend reading 
>section 8.19 of the C# standard, available at
>
>http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf 


A bit OT. Under the hood C# nullable types are structs with an
additional bool member. ? is just a syntactic sugar for the templated
System.Nullable struct. Here is a quickly hacked together example of
how nullable types could be implemented in D using templates.

struct Nullable(T)
{
	alias typeof(*this) Type;

	T value;
	bool isNull = true;

	Type opAssign(T v)
	{
		value = v;
		isNull = false;
		return *this;
	}

	static Type opCall(T v)
	{
	    Type ret;
	    ret.value = v;
	    ret.isNull = false;
	    return ret;
	}

	/*
	Hacks to allow null keyword in assignments/comparisons
	if you really want it
	*/

	Type opAssign(void* v)
	{
	    assert(v == null);
	    isNull = true;
	    return *this;
	}

	int opEquals(void* v)
	{
	    assert(v == null);
	    return isNull;
	}

	T getValueOrDefault()
	{
	    return isNull ? T.init : value;
	}

	T ifNull(T v)
	{
	    return isNull ? v : value;
	}

	/*
	etc.
	opImplicitCasts and struct interfaces will be useful here
	*/
}

class DataReader
{
    Nullable!(T) get(T)(char[] field)
    {
        Nullable!(T) ret;
        return ret;
    }
}

void main()
{
    auto data = new DataReader;

    auto id = data.get!(long)("id");
    assert(id == null);

    id = 20;
    assert(id != null);

    id = null;

    // a replacement for 'long x = id ?? -1'
    long x = id.ifNull(-1);
    assert (x == -1);
}

I'm sure DB people already use something like that.



More information about the Digitalmars-d mailing list