I modified the Adam D Ruppes notnull.dbit module to allow the assignment of class instances of NotNullinherited classes to base class instances NotNullusing the constructor
typeof(this) opAssign(U)(NotNull!U rhs) @safe pure nothrow if (isAssignable!(T, U)) {
this._value = rhs._value;
return this;
}
This allows
unittest
{
class A {}
class B : A {}
NotNull!B b = assumeNotNull(new B);
NotNull!A a = assumeNotNull(new A);
a = b;
assert(a is b);
}
However, I did not understand how to resolve
unittest
{
class A {}
class B : A {}
void f(NotNull!A a) {}
NotNull!B b = assumeNotNull(new B);
f(b);
}
for compilation, which I think should work automatically.
For this work, obviously, is not enough alias this.
How to do it?
See also: http://forum.dlang.org/thread/ aprsozwvnpnchbaswjxd@forum.dlang.org # post-aprsozwvnpnchbaswjxd: 40forum.dlang.org
The full source code of the module notnull.dfollows:
#!/usr/bin/env rdmd-dev-module
module notnull;
import std.traits: isAssignable;
alias NotNullable(T) = isAssignable!(T, typeof(null));
struct NotNull(T) if (NotNullable!T)
{
@disable this();
typeof(this) opAssign(U)(NotNull!U rhs) @safe pure nothrow if (isAssignable!(T, U)) {
this._value = rhs._value;
return this;
}
NotNull!U opCast(U)() @safe pure nothrow if (isAssignable!(U, T)) {
return NotNull!_value;
}
this(T value) @safe pure nothrow
{
assert(value !is null);
_value = value;
}
@disable this(typeof(null));
@disable typeof(this) opAssign(typeof(null));
private T _value;
@property inout(T) _valueHelper() inout
{
assert(_value !is null);
return _value;
}
alias _valueHelper this;
}
NotNull!T assumeNotNull(T)(T t) if (NotNullable!T)
{
return NotNull!T(t);
}
NotNull!T enforceNotNull(T, string file = __FILE__, size_t line = __LINE__)(T t) if (NotNullable!T)
{
import std.exception: enforce;
enforce(t !is null, "t is null!", file, line);
return NotNull!T(t);
}
unittest
{
import core.exception;
import std.exception;
void NotNullCompiliationTest1()()
{
NotNull!(int*) defaultInitiliation;
}
assert(!__traits(compiles, NotNullCompiliationTest1!()()));
void NotNullCompiliationTest2()()
{
NotNull!(int*) defaultInitiliation = null;
}
assert(!__traits(compiles, NotNullCompiliationTest2!()()));
int dummy;
NotNull!(int*) foo = &dummy;
assert(!__traits(compiles, foo = null));
int* test;
test = &dummy;
foo = assumeNotNull(test);
void bar(int* a) {}
bar(test);
bar(foo);
void takesNotNull(NotNull!(int*) a) { }
assert(!__traits(compiles, takesNotNull(test)));
takesNotNull(foo);
takesNotNull(assumeNotNull(test));
assert(!__traits(compiles, takesNotNull(assumeNotNull(null))));
test = null;
assertThrown!AssertError(takesNotNull(assumeNotNull(test)));
void takesConstNotNull(in NotNull!(int *) a) {}
test = &dummy;
takesConstNotNull(assumeNotNull(test));
NotNull!(int*) foo2 = foo;
foo2 = foo;
}
unittest
{
class A {}
class B : A {}
NotNull!B b = assumeNotNull(new B);
NotNull!A a = assumeNotNull(new A);
a = b;
assert(a is b);
}