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.