www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Efficient way to create/copy immutable struct instance with modified

reply Merlin Diavova <md mdiavov.com> writes:
Hi all,

I'm trying to figure out the most efficient way to create 
modified instances of immutable structs.

Currently, I'm doing the following:

```d
immutable struct Node {
	string label;
	Node parentNode;
	NetworkPort port;

	auto withLabel(string newLabel)
	{
		return Node(newLabel, this.parentNode, this.port);
	}

	auto withParentNode(Node newParentNode)
	{
		return Node(this.label, newParentNode, this.port);
	}

	auto withNetworkPort(NetworkPort newPort)
	{
		return Node(this.label, this.parentNode, newPort);
	}
}
```
Coming from a scripting language the above makes the most sense.
In D, this an efficient way to do it? Are there any best 
practices around this?

Thanks in advance

Merlin
Nov 19 2021
parent Adam D Ruppe <destructionator gmail.com> writes:
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.
Nov 19 2021