Efficient way to create/copy immutable struct instance with modified data

Adam D Ruppe destructionator at gmail.com
Fri Nov 19 18:11:01 UTC 2021


On Friday, 19 November 2021 at 17:38:53 UTC, Merlin Diavova wrote:
> I'm trying to figure out the most efficient way to create 
> modified instances of immutable structs.

This might not be the best way but it is a kinda cool trick 
anyway: structs have a `tupleof` property you can slice. So you 
can do things like:

Node(old_node.tupleof[0 .. argIndex], replacement, 
old_node.tupleof[argIndex + 1 .. $]);

Where argIndex can be like 0 to replace the first item in the 
struct, or 1 to replace the second.

It is possible to look this up using reflection and kinda 
automate this if you wanted.

```
mixin template Replaceable() {
         // returns a replaced thing when you use it as 
`with_someField`
         typeof(this) opDispatch(string s, T)(T replacement) 
if(s.length > 5 && s[0 .. 5] == "with_")
         {
                 static foreach(idx, member; typeof(this).tupleof) 
{
                         static if(__traits(identifier, member) == 
s[5 .. $])
                                 enum argIndex = idx;
                 }
                 // if the arg is not found you will get an ugly 
error message here about undefined
                 // argIndex.... meh.
                 return typeof(this)(this.tupleof[0 .. argIndex], 
replacement, this.tupleof[argIndex + 1 .. $]);
         }
}

immutable struct Node {
         string label;
         Node* parentNode;
         int port;

         mixin Replaceable; // add the ugly generic code from the 
top
}

void main() {
         Node i = Node("one", null, 4);
         Node i2 = i.with_port(6); // and now use it like this
         assert(i2.label == "one");
         assert(i2.port == 6);
}
```


I did `with_` instead of camelCase to avoid having to mess with 
case comparisons on the name.


More information about the Digitalmars-d-learn mailing list