Nullable types
Mehrdad
wfunction at hotmail.com
Wed Jun 20 09:31:33 PDT 2012
I've made my own nullable type, and I think it works a bit more
naturally than Phobos's in some cases, since it takes advantage
of alias this and typeof(null) and some stuff.
(It's designed to mimic C#'s nullable types.)
Would it be a good addition to Phobos? If not, ideas on what
could be improved?
//=============================
private struct NullableTag { }
template isNullable(T) { enum isNullable = __traits(compiles,
T.init == null); }
template Nullable(T)
{
static if (isNullable!(T)) { alias T Nullable; }
else
{
struct Nullable
{
// To tell if something is Nullable
private alias .NullableTag NullableTag;
private T _value;
private bool _hasValue;
public this(A)(auto ref A value)
inout /+pure @safe nothrow+/
{
this._value = value;
this._hasValue = true;
}
public this(A : typeof(null))(A)
inout /+pure @safe nothrow+/ { }
public @property ref const(bool) hasValue()
const /+pure @safe nothrow+/
{ return this._hasValue; }
public @property ref inout(T) value()
inout /+pure @safe+/
{ return *(this._hasValue ? &this._value : null); }
public int opCmp(RHS)(scope RHS rhs)
const /+pure @safe nothrow+/
if (!is(RHS.NullableTag == NullableTag))
{
int r;
if (this.hasValue)
{
static if (__traits(compiles, this._value.opCmp(rhs)))
{ r = this._value.opCmp(rhs._value); }
else
{ r = this._value < rhs ? -1 : (this._value > rhs ? 1 : 0); }
}
else { r = -1; }
return r;
}
public int opCmp(RHS)(scope RHS rhs)
const /+pure @safe nothrow+/
if (is(RHS.NullableTag == NullableTag))
{
int r;
if (this.hasValue && rhs.hasValue)
{ r = 0; }
else if (this.hasValue && !rhs.hasValue)
{ r = 1; }
else if (!this.hasValue && rhs.hasValue)
{ r = -1; }
else { r = this == rhs._value; }
return r;
}
public int opCmp(RHS : typeof(null))(scope RHS)
const /+pure @safe nothrow+/
{ return this.hasValue ? 1 : 0; }
public bool opEquals(RHS)(scope RHS rhs)
const /+pure @safe nothrow+/
if (!is(RHS.NullableTag == NullableTag))
{ return this.hasValue && this._value == rhs; }
public bool opEquals(RHS)(scope RHS rhs)
const /+pure @safe nothrow+/
if (is(RHS.NullableTag == NullableTag))
{
return this.hasValue == rhs.hasValue &&
this._value == rhs._value;
}
public bool opEquals(RHS : typeof(null))(scope RHS)
const /+pure @safe nothrow+/
{ return !this.hasValue; }
static if (!is(T == const(T)))
{
public auto ref opAssign(RHS)(auto ref RHS rhs)
/+pure @safe nothrow+/
{
this._value = rhs;
this._hasValue = true;
return rhs;
}
public auto ref opAssign(RHS : typeof(null))(auto ref RHS rhs)
/+pure @safe nothrow+/
{
this._value = T.init;
this._hasValue = false;
return rhs;
}
}
public alias value this;
}
}
}
unittest
{
Nullable!int a = null;
Nullable!int b = 5;
int c = 5;
assert(a != b);
assert(b == c);
assert(a == null);
assert(b != null);
assert(b + 1 == 6);
struct S
{
public bool opEquals(S) const pure @safe nothrow
{ return true; }
public bool opEquals(int) const pure @safe nothrow
{ return true; }
}
Nullable!S s;
assert(s != 0);
assert(s.opCmp(null) == 0);
assert(a.opCmp(null) == 0);
assert(b.opCmp(null) > 0);
assert(b.opCmp(6) < 0);
assert(b.opCmp(5) == 0);
}
@property Nullable!(T) nullable(T)(auto ref T value) /+pure @safe
nothrow+/
{
Nullable!(T) result = value;
return result;
}
More information about the Digitalmars-d
mailing list