Last active
August 29, 2015 14:13
-
-
Save JakobOvrum/0ebb37f8e4626b35f1c7 to your computer and use it in GitHub Desktop.
Library implementation of the `final` storage class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
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