On Monday, 22 January 2024 at 08:27:36 UTC, Joel wrote:
```d
import std;

struct Person {
    string name, email;
    ulong age;
    auto withName(string name) { this.name=name; return this; }
auto withEmail(string email) { this.email=email; return this; }
    auto withAge(ulong age) { this.age=age; return this; }
}

void main() {
    Person p;
p.withName("Tom").withEmail("joel...@gmail.com").withAge(44);
    writeln(p);
}
```

I had reason to need this to work a while ago and `opDispatch` came in very handy. I was able to cook up one that forwarded calls to other members in a struct, while returning `this` by ref, allowing for chaining calls. I use it with UDAs.

(Scroll to the unit tests for examples.)

```d
/++
Mixin template generating an `opDispatch` redirecting calls to members whose names match the passed variable string but with an underscore prepended.
 +/
mixin template UnderscoreOpDispatcher()
{
    ref auto opDispatch(string var, T)(T value)
    {
import std.traits : isArray, isAssociativeArray, isSomeString;

        enum realVar = '_' ~ var;
        alias V = typeof(mixin(realVar));

        static if (isAssociativeArray!V)
        {
            // Doesn't work with AAs without library solutions
        }
        else static if (isArray!V && !isSomeString!V)
        {
            mixin(realVar) ~= value;
        }
        else
        {
            mixin(realVar) = value;
        }

        return this;
    }

    auto opDispatch(string var)() inout
    {
        enum realVar = '_' ~ var;
        return mixin(realVar);
    }
}

///
unittest
{
    struct Foo
    {
        int _i;
        string _s;
        bool _b;
        string[] _add;
        alias wordList = _add;

        mixin UnderscoreOpDispatcher;
    }

    Foo f;
    f.i = 42;         // f.opDispatch!"i"(42);
    f.s = "hello";    // f.opDispatch!"s"("hello");
    f.b = true;       // f.opDispatch!"b"(true);
    f.add("hello");   // f.opDispatch!"add"("hello");
    f.add("world");   // f.opDispatch!"add"("world");

    assert(f.i == 42);
    assert(f.s == "hello");
    assert(f.b);
    assert(f.wordList == [ "hello", "world" ]);

    auto f2 = Foo()
        .i(9001)
        .s("world")
        .b(false)
        .add("hello")
        .add("world");

    assert(f2.i == 9001);
    assert(f2.s == "world");
    assert(!f2.b);
    assert(f2.wordList == [ "hello", "world" ]);
}
```

You could trivially adapt it to use a `withName`, `withEmail` calling scheme instead of the underscore thing.

Reply via email to