| |
| Posted by Adam D Ruppe in reply to Merlin Diavova | PermalinkReply |
|
Adam D Ruppe
Posted in reply to Merlin Diavova
| 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.
|