Skip to content

Instantly share code, notes, and snippets.

@JakobOvrum
Last active August 29, 2015 14:13
Show Gist options
  • Save JakobOvrum/0ebb37f8e4626b35f1c7 to your computer and use it in GitHub Desktop.
Save JakobOvrum/0ebb37f8e4626b35f1c7 to your computer and use it in GitHub Desktop.
Library implementation of the `final` storage class
/**
Type constructor for final variables.
A final variable is "head-const"; it cannot be directly
mutated or rebound, but references reached through the variable
are typed with their original mutability.
*/
struct Final(T)
if(!is(T == const) && !is(T == immutable))
{
private:
T data;
public:
/// $(D Final) subtypes $(D T) as an rvalue.
inout(T) Final_get() inout pure nothrow @nogc @safe
{
return data;
}
alias Final_get this; /// Ditto
///
this(T data)
{
this.data = data;
}
/// Ditto
this(Args...)(auto ref Args args)
if(__traits(compiles, T(args)))
{
this.data = data;
}
// Making `opAssign` a template like this gives better error messages.
///
@disable void opAssign(Other)(Other other);
}
/// Ditto
template Final(T) if(is(T == const) || is(T == immutable))
{
alias Final = T;
}
/// $(D Final) can be used to create class references which cannot be rebound:
unittest
{
static class A
{
int i;
this(int i)
{
this.i = i;
}
}
Final!A a = new A(42);
assert(a.i == 42);
// a = new C(24); // Reassignment is illegal,
a.i = 24; // But fields are still mutable.
assert(a.i == 24);
}
/// $(D Final) can also be used to create read-only data fields
/// without using transitive immutability:
unittest
{
static class A
{
int i;
this(int i)
{
this.i = i;
}
}
static class B
{
Final!A a;
this(A a)
{
this.a = a; // Construction, thus allowed.
}
}
auto b = new B(new A(42));
assert(b.a.i == 42);
// b.a = new A(24); // Reassignment is illegal,
b.a.i = 24; // but `a` is still mutable.
assert(b.a.i == 24);
}
unittest
{
static class A { int i; }
static assert(!is(Final!A == A));
static assert(is(Final!(const A) == const A));
static assert(is(Final!(immutable A) == immutable A));
Final!A a = new A;
static assert(!__traits(compiles, a = new A));
assert(a.i == 0);
a.i = 42;
assert(a.i == 42);
Final!int i = 42;
static assert(!__traits(compiles, i = 24));
assert(i == 42);
int iCopy = i;
assert(iCopy == 42);
static struct S
{
this(int i){}
this(string s){}
}
Final!S sint = 42;
Final!S sstr = "foo";
static assert(!__traits(compiles, sint = sstr));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment