GenerateThis

GenerateThis is a mixin string that automatically generates a this() function, customizable with UDA.

enum string GenerateThis;

Examples

class Class
{
    int field;

    mixin(GenerateThis);
}

auto obj = new Class(5);

obj.field.shouldEqual(5);
class Class
{
    int field;

    mixin(GenerateThis);
}

class Child : Class
{
    int field2;

    mixin(GenerateThis);
}

auto obj = new Child(5, 8);

obj.field.shouldEqual(5);
obj.field2.shouldEqual(8);
class Class
{
    int field;

    void method() { }

    mixin(GenerateThis);
}

auto obj = new Class(5);

obj.field.shouldEqual(5);
class Class
{
    int[] array;

    mixin(GenerateThis);
}

auto array = [2, 3, 4];
auto obj = new Class(array);

array[0] = 1;
obj.array[0].shouldEqual(2);
import std.typecons : Nullable, nullable;

class Class
{
    Nullable!(int[]) array;

    mixin(GenerateThis);
}

auto array = [2, 3, 4];
auto obj = new Class(array.nullable);

array[0] = 1;
obj.array.get[0].shouldEqual(2);

obj = new Class(Nullable!(int[]).init);
obj.array.isNull.shouldBeTrue;
class Class
{
    int[int] array;

    mixin(GenerateThis);
}

auto array = [2: 3];
auto obj = new Class(array);

array[2] = 4;
obj.array.shouldEqual([2: 3]);
class Class
{
    @(This.Default!5)
    int value = 5;

    mixin(GenerateThis);
}

auto obj1 = new Class();

obj1.value.shouldEqual(5);

auto obj2 = new Class(6);

obj2.value.shouldEqual(6);
struct Struct
{
    mixin(GenerateThis);
}

auto strct = Struct();
import std.conv : to;

class Class
{
    @(This.Default!(() => new Object))
    Object obj;

    mixin(GenerateThis);
}

auto obj1 = new Class();
auto obj2 = new Class();

(cast(void*) obj1.obj).shouldNotEqual(cast(void*) obj2.obj);
class Parent
{
    int field1;

    @(This.Default!2)
    int field2 = 2;

    mixin(GenerateThis);
}

class Child : Parent
{
    int field3;

    @(This.Default!4)
    int field4 = 4;

    mixin(GenerateThis);
}

auto obj = new Child(1, 2, 3, 4);

obj.field1.shouldEqual(1);
obj.field3.shouldEqual(2);
obj.field4.shouldEqual(3);
obj.field2.shouldEqual(4);
class Class
{
    static int field1;
    int field2;

    mixin(GenerateThis);
}

auto obj = new Class(5);

obj.field1.shouldEqual(0);
obj.field2.shouldEqual(5);
class Class
{
    immutable(Object)[] array;

    mixin(GenerateThis);
}
@(This.Private)
class PrivateClass
{
    mixin(GenerateThis);
}

@(This.Protected)
class ProtectedClass
{
    mixin(GenerateThis);
}

@(This.Package)
class PackageClass
{
    mixin(GenerateThis);
}

@(This.Package("boilerplate"))
class SubPackageClass
{
    mixin(GenerateThis);
}

class PublicClass
{
    mixin(GenerateThis);
}

static assert(__traits(getProtection, PrivateClass.__ctor) == "private");
static assert(__traits(getProtection, ProtectedClass.__ctor) == "protected");
static assert(__traits(getProtection, PackageClass.__ctor) == "package");
// getProtection does not return the package name of a package() attribute
// static assert(__traits(getProtection, SubPackageClass.__ctor) == `package(boilerplate)`);
static assert(__traits(getProtection, PublicClass.__ctor) == "public");
@(This.Private)
class PrivateClass
{
    mixin(GenerateThis);
}

@(This.Protected)
class ProtectedClass
{
    mixin(GenerateThis);
}

@(This.Package)
class PackageClass
{
    mixin(GenerateThis);
}

@(This.Package("boilerplate"))
class SubPackageClass
{
    mixin(GenerateThis);
}

class PublicClass
{
    mixin(GenerateThis);
}

static assert(__traits(getProtection, PrivateClass.Builder) == "private");
static assert(__traits(getProtection, ProtectedClass.Builder) == "protected");
static assert(__traits(getProtection, PackageClass.Builder) == "package");
static assert(__traits(getProtection, PublicClass.Builder) == "public");
class Class
{
    @(This.Default!(() => new Object))
    Object foo;

    mixin(GenerateThis);
}

((new Class).foo !is null).shouldBeTrue;
class Class
{
    @(This.Default)
    string s;

    @(This.Default)
    int i;

    mixin(GenerateThis);
}

(new Class()).i.shouldEqual(0);
(new Class()).s.shouldEqual(string.init);
class Class
{
    @(This.Exclude)
    int i = 5;

    mixin(GenerateThis);
}

(new Class).i.shouldEqual(5);
struct Struct
{
}

class Class
{
    Struct[] values_;

    mixin(GenerateThis);
}

const Struct[] constValues;
auto obj = new Class(constValues);
class Class
{
    int a;

    @property int foo() const
    {
        return 0;
    }

    mixin(GenerateThis);
}

static assert(__traits(compiles, new Class(0)));
static assert(!__traits(compiles, new Class(0, 0)));
class Class
{
    @(This.Init!5)
    int field1;

    @(This.Init!(() => 8))
    int field2;

    mixin(GenerateThis);
}

auto obj = new Class;

obj.field1.shouldEqual(5);
obj.field2.shouldEqual(8);
class Class
{
    int field1;

    @(This.Init!(self => self.field1 + 5))
    int field2;

    mixin(GenerateThis);
}

auto obj = new Class(5);

obj.field1.shouldEqual(5);
obj.field2.shouldEqual(10);
class Class1
{
    @(This.Init!(self => new Object))
    Object object;

    mixin(GenerateThis);
}

class Class2
{
    @(This.Init!(() => new Object))
    Object object;

    mixin(GenerateThis);
}

class Class3 : Class2
{
    mixin(GenerateThis);
}
static class Class
{
    int field1;
    int field2;
    int field3;

    mixin(GenerateThis);
}

auto obj = {
    with (Class.Builder())
    {
        field1 = 1;
        field2 = 2;
        field3 = 3;
        return value;
    }
}();

with (obj)
{
    field1.shouldEqual(1);
    field2.shouldEqual(2);
    field3.shouldEqual(3);
}
static class Class
{
    int field1;
    int field2;
    int field3;

    mixin(GenerateThis);
}

auto obj = {
    with (Class.Builder())
    {
        field3 = 1;
        field1 = 2;
        field2 = 3;
        return value;
    }
}();

with (obj)
{
    field1.shouldEqual(2);
    field2.shouldEqual(3);
    field3.shouldEqual(1);
}
static class Class
{
    int field1;
    @(This.Default!5)
    int field2;
    int field3;

    mixin(GenerateThis);
}

// constructor is this(field1, field3, field2 = 5)
auto obj = {
    with (Class.Builder())
    {
        field1 = 1;
        field3 = 3;
        return value;
    }
}();

with (obj)
{
    field1.shouldEqual(1);
    field2.shouldEqual(5);
    field3.shouldEqual(3);
}
struct Struct
{
    int field1;
    int field2;
    int field3;

    mixin(GenerateThis);
}

auto value = {
    with (Struct.Builder())
    {
        field1 = 1;
        field3 = 3;
        field2 = 5;
        return value;
    }
}();

static assert(is(typeof(value) == Struct));

with (value)
{
    field1.shouldEqual(1);
    field2.shouldEqual(5);
    field3.shouldEqual(3);
}
struct Struct
{
    private int a_;

    mixin(GenerateThis);
}

auto builder = Struct.Builder();

builder.a = 1;

auto value = builder.value;

value.shouldEqual(Struct(1));
struct Struct1
{
    int a;
    int b;

    mixin(GenerateThis);
}

struct Struct2
{
    int c;
    Struct1 struct1;
    int d;

    mixin(GenerateThis);
}

auto builder = Struct2.Builder();

builder.struct1.a = 1;
builder.struct1.b = 2;
builder.c = 3;
builder.d = 4;

auto value = builder.value;

static assert(is(typeof(value) == Struct2));

with (value)
{
    struct1.a.shouldEqual(1);
    struct1.b.shouldEqual(2);
    c.shouldEqual(3);
    d.shouldEqual(4);
}
struct Struct1
{
    int a;
    int b;

    mixin(GenerateThis);
}

struct Struct2
{
    int c;
    @(This.Default!(Struct1(3, 4)))
    Struct1 struct1;
    int d;

    mixin(GenerateThis);
}

auto builder = Struct2.Builder();

builder.c = 1;
builder.d = 2;

builder.value.shouldEqual(Struct2(1, 2, Struct1(3, 4)));
struct Struct1
{
    int a;
    int b;

    mixin(GenerateThis);
}

struct Struct2
{
    int c;
    Struct1 struct1;
    int d;

    mixin(GenerateThis);
}

auto builder = Struct2.Builder();

builder.struct1 = Struct1(2, 3);
builder.c = 1;
builder.d = 4;

builder.value.shouldEqual(Struct2(1, Struct1(2, 3), 4));
struct Struct1
{
    int value;

    mixin(GenerateThis);
}

struct Struct2
{
    Struct1[] array;

    mixin(GenerateThis);
}

auto builder = Struct2.Builder();

builder.array[0].value = 1;
builder.array[1].value = 2;

builder.value.shouldEqual(Struct2([Struct1(1), Struct1(2)]));
struct Struct1
{
    int value;

    mixin(GenerateThis);
}

struct Struct2
{
    Struct1[] array;

    mixin(GenerateThis);
}

auto builder = Struct2.Builder();

builder.array ~= Struct1(1);
builder.array ~= Struct1(2);

builder.value.shouldEqual(Struct2([Struct1(1), Struct1(2)]));
struct Struct1
{
    int a;
    int b;

    mixin(GenerateThis);
}

struct Struct2
{
    Struct1 struct1;

    mixin(GenerateThis);
}

auto builder = Struct2.Builder();

builder.struct1 = Struct1(2, 3);
builder.struct1.b = 4;

builder.value.shouldEqual(Struct2(Struct1(2, 4)));
import core.exception : AssertError;

struct Struct1
{
    int a;

    private Object[] b_;

    mixin(GenerateThis);
}

struct Struct2
{
    Struct1 struct1;

    mixin(GenerateThis);
}

// this should at least compile, despite the BuilderFrom hack not working with Struct1
auto builder = Struct2.Builder();

builder.struct1 = Struct1(2, null);

void set()
{
    builder.struct1.b = null;
}

set().shouldThrow!AssertError(
    "Builder: cannot set sub-field directly since field is already " ~
    "being initialized by value (and BuilderFrom is unavailable in Struct1)");
import core.exception : AssertError;

struct Struct1
{
    int a;
    int b;

    mixin(GenerateThis);
}

struct Struct2
{
    Struct1 struct1;

    mixin(GenerateThis);
}

auto builder = Struct2.Builder();

builder.struct1.b = 4;

void set()
{
    builder.struct1 = Struct1(2, 3);
}
set().shouldThrow!AssertError("Builder: cannot set field by value since a subfield has already been set.");
struct Struct
{
    const int a;

    mixin(GenerateThis);
}

with (Struct.Builder())
{
    a = 5;

    value.shouldEqual(Struct(5));
}
static struct Struct1
{
    ~this() pure @safe @nogc nothrow { }
}

struct Struct2
{
    Struct1 struct1;

    mixin(GenerateThis);
}

with (Struct2.Builder())
{
    struct1 = Struct1();

    value.shouldEqual(Struct2(Struct1()));
}
import std.typecons : Nullable, nullable;

struct Struct
{
    const Nullable!int a;

    mixin(GenerateThis);
}

with (Struct.Builder())
{
    a = 5;

    value.shouldEqual(Struct(5.nullable));
}
import std.typecons : Nullable, nullable;

struct Struct1
{
    int a;

    mixin(GenerateThis);
}

struct Struct2
{
    @(This.Default)
    Nullable!Struct1 b;

    mixin(GenerateThis);
}

with (Struct2.Builder())
{
    value.shouldEqual(Struct2(Nullable!Struct1()));

    b.a = 5;

    value.shouldEqual(Struct2(Nullable!Struct1(Struct1(5))));
}
import std.typecons : Nullable, nullable;

struct Struct1
{
    mixin(GenerateThis);
}

struct Struct2
{
    @(This.Default)
    Nullable!Struct1 value;

    mixin(GenerateThis);
}

with (Struct2.Builder())
{
    builderValue.shouldEqual(Struct2());

    value = Struct1();

    builderValue.shouldEqual(Struct2(Struct1().nullable));
}

with (Struct2.Builder())
{
    value = Nullable!Struct1();

    builderValue.shouldEqual(Struct2());
}
import std.typecons : Nullable, nullable;

struct Struct
{
    private int a_;

    int[] b;

    mixin(GenerateThis);
}

const originalValue = Struct(2, [3]);

with (originalValue.BuilderFrom())
{
    a = 5;

    value.shouldEqual(Struct(5, [3]));
}
import std.typecons : Nullable, nullable;

struct Struct
{
    private int value_;

    mixin(GenerateThis);
}

with (Struct.Builder())
{
    value = 5;

    builderValue.shouldEqual(Struct(5));
}
import std.typecons : Nullable, nullable;

static struct Inner
{
    private int i_;

    @disable this();

    mixin(GenerateThis);
}

static struct Struct
{
    private Inner inner_;

    mixin(GenerateThis);
}

with (Struct.Builder())
{
    inner.i = 3;

    value.shouldEqual(Struct(Inner(3)));
}

Meta