Skip to content

Commit

Permalink
Add style changes to HeadConst
Browse files Browse the repository at this point in the history
  • Loading branch information
wilzbach committed Aug 29, 2016
1 parent 6db4de4 commit e7612f9
Showing 1 changed file with 87 additions and 86 deletions.
173 changes: 87 additions & 86 deletions std/experimental/typecons.d
Expand Up @@ -803,92 +803,93 @@ private template findCovariantFunction(alias finfo, Source, Fs...)
enum ptrdiff_t findCovariantFunction = x;
}

/++
+ Type constructor for head-const variables.
+
+ Head-const variables cannot be directly mutated or rebound, but references
+ reached through the variable are typed with their original mutability.
+ It is equivalent to $(D final) variables in D1 and Java, as well as
+ $(D readonly) variables in C#.
+
+ When $(D T) is a $(D const) or $(D immutable) type, $(D HeadConst) aliases
+ to $(D T).
+/
struct HeadConst(T)
if (!is(T == const) && !is(T == immutable))
{
import std.typecons : Proxy;
/**
Type constructor for final (aka head-const) variables.
private T HeadConst_value;
mixin Proxy!HeadConst_value;
Final variables cannot be directly mutated or rebound, but references
reached through the variable are typed with their original mutability.
It is equivalent to `final` variables in D1 and Java, as well as
`readonly` variables in C#.
/++
+ Construction is forwarded to the underlying type.
+/
this(T other)
When `T` is a `const` or `immutable` type, `Final` aliases
to `T`.
*/
template Final(T)
{
static if (is(T == const) || is(T == immutable))
alias Final = T;
else
{
struct Final
{
this.HeadConst_value = other;
}
import std.typecons : Proxy;

/// Ditto
this(Args...)(auto ref Args args)
if (__traits(compiles, T(args)))
{
static assert((!is(T == struct) && !is(T == union)) || !isNested!T,
"Non-static nested type " ~ fullyQualifiedName!T ~ " must be " ~
"constructed explicitly at the call-site (e.g. auto s = " ~
"headConst(" ~ T.stringof ~ "(...));)");
this.HeadConst_value = T(args);
}
private T final_value;
mixin Proxy!final_value;

// Attaching function attributes gives less noisy error messages
pure nothrow @safe @nogc
{
/++
+ All operators, including member access, are forwarded to the
+ underlying value of type $(D T) except for these mutating operators,
+ which are disabled.
+/
@disable void opAssign(Other)(Other other);
@disable void opOpAssign(string op, Other)(Other other); /// Ditto
@disable void opUnary(string op : "--")(); /// Ditto
@disable void opUnary(string op : "++")(); /// Ditto
}
/**
* Construction is forwarded to the underlying type.
*/
this(T other)
{
this.final_value = other;
}

/++
+
+ $(D HeadConst!T) implicitly converts to an rvalue of type $(D T) through
+ $(D AliasThis).
+/
inout(T) HeadConst_get() inout
{
return HeadConst_value;
}
/// Ditto
this(Args...)(auto ref Args args)
if (__traits(compiles, T(args)))
{
static assert((!is(T == struct) && !is(T == union)) || !isNested!T,
"Non-static nested type " ~ fullyQualifiedName!T ~ " must be " ~
"constructed explicitly at the call-site (e.g. auto s = " ~
"makeFinal(" ~ T.stringof ~ "(...));)");
this.final_value = T(args);
}

/// Ditto
alias HeadConst_get this;
// Attaching function attributes gives less noisy error messages
pure nothrow @safe @nogc @disable
{
/++
+ All operators, including member access, are forwarded to the
+ underlying value of type `T` except for these mutating operators,
+ which are disabled.
+/
void opAssign(Other)(Other other);
void opOpAssign(string op, Other)(Other other); /// Ditto
void opUnary(string op : "--")(); /// Ditto
void opUnary(string op : "++")(); /// Ditto
}

auto ref T opUnary(string op)()
if (__traits(compiles, mixin(op ~ "T.init")))
{
return mixin(op ~ "this.HeadConst_value");
/**
*
* `Final!T` implicitly converts to an rvalue of type `T` through
* `AliasThis`.
*/
inout(T) final_get() inout
{
return final_value;
}

/// Ditto
alias final_get this;

/// Ditto
T opUnary(string op)()
if (__traits(compiles, mixin(op ~ "T.init")))
{
return mixin(op ~ "this.final_value");
}
}
}

/// Ditto
template HeadConst(T)
if (is(T == const) || is(T == immutable))
{
alias HeadConst = T;
}

/// Ditto
HeadConst!T headConst(T)(T t)
Final!T makeFinal(T)(T t)
{
return HeadConst!T(t);
return Final!T(t);
}

/// $(D HeadConst) can be used to create class references which cannot be rebound:
/// `Final` can be used to create class references which cannot be rebound:
pure nothrow @safe unittest
{
static class A
Expand All @@ -901,16 +902,16 @@ pure nothrow @safe unittest
}
}

auto a = headConst(new A(42));
auto a = makeFinal(new A(42));
assert(a.i == 42);

// a = new C(24); // Reassignment is illegal,
//a = new A(24); // Reassignment is illegal,
a.i = 24; // But fields are still mutable.

assert(a.i == 24);
}

/// $(D HeadConst) can also be used to create read-only data fields without using transitive immutability:
/// `Final` can also be used to create read-only data fields without using transitive immutability:
pure nothrow @safe unittest
{
static class A
Expand All @@ -925,7 +926,7 @@ pure nothrow @safe unittest

static class B
{
HeadConst!A a;
Final!A a;

this(A a) pure nothrow @nogc @safe
{
Expand All @@ -945,11 +946,11 @@ pure nothrow @safe unittest
pure nothrow @safe unittest
{
static class A { int i; }
static assert(!is(HeadConst!A == A));
static assert(is(HeadConst!(const A) == const A));
static assert(is(HeadConst!(immutable A) == immutable A));
static assert(!is(Final!A == A));
static assert(is(Final!(const A) == const A));
static assert(is(Final!(immutable A) == immutable A));

HeadConst!A a = new A;
Final!A a = new A;
static assert(!__traits(compiles, a = new A));

static void foo(ref A a) pure nothrow @safe @nogc {}
Expand All @@ -959,7 +960,7 @@ pure nothrow @safe unittest
a.i = 42;
assert(a.i == 42);

HeadConst!int i = 42;
Final!int i = 42;
static assert(!__traits(compiles, i = 24));
static assert(!__traits(compiles, --i));
static assert(!__traits(compiles, ++i));
Expand All @@ -979,11 +980,11 @@ pure nothrow @safe unittest
this(int i, string s, float f){ this.i = i; }
}

HeadConst!S sint = 42;
HeadConst!S sstr = "foo";
Final!S sint = 42;
Final!S sstr = "foo";
static assert(!__traits(compiles, sint = sstr));

auto sboth = HeadConst!S(42, "foo", 3.14);
auto sboth = Final!S(42, "foo", 3.14);
assert(sboth.i == 42);

sboth.i = 24;
Expand All @@ -996,8 +997,8 @@ pure nothrow @safe unittest
}

// Nested structs must be constructed at the call-site
static assert(!__traits(compiles, HeadConst!NestedS(6)));
auto s = headConst(NestedS(6));
static assert(!__traits(compiles, Final!NestedS(6)));
auto s = makeFinal(NestedS(6));
assert(s.i == 6);
assert(s.get == 30);

Expand All @@ -1010,14 +1011,14 @@ pure nothrow @safe unittest
int get() { return sboth.i + i; }
}

auto c = headConst(new NestedC(6));
auto c = makeFinal(new NestedC(6));
assert(c.i == 6);
assert(c.get == 30);
}

pure nothrow @safe unittest
{
auto arr = headConst([1, 2, 3]);
auto arr = makeFinal([1, 2, 3]);
static assert(!__traits(compiles, arr = null));
static assert(!__traits(compiles, arr ~= 4));
assert((arr ~ 4) == [1, 2, 3, 4]);
Expand Down

0 comments on commit e7612f9

Please sign in to comment.