Setting field of struct object

Anonymouse zorael at gmail.com
Thu Feb 1 23:00:22 UTC 2024


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("joelcnz at 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.


More information about the Digitalmars-d-learn mailing list