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