How to make a struct containing an associative array to deeply copy (for repeated usage in foreach) ?

rkompass rkompass at gmx.de
Fri Mar 15 20:36:56 UTC 2024


On Friday, 15 March 2024 at 17:15:56 UTC, monkyyy wrote:
> On Friday, 15 March 2024 at 09:03:25 UTC, rkompass wrote:
>> @Monkyyy: I adopted your solution, it is perfect.
>>
>> I only have one problem left:
>>
>> The foreach loop with associative arrays has two cases:
>>
>> `foreach(key, val; arr)` and `foreach(x; arr)`.
>> In the second case only the values are iterated.
>> With the present solution the iteration delivers (key, val) 
>> tuples.
>
> That will not be fixed in d2 ranges and has no good solutions; 
> and my affect over d3 seems to be none. You could ask around 
> for the "opApply" solution but I dont know it well (and prefer 
> ranges)
>
> d2 Ranges are based on a simplification of stl's ideas and stl 
> doesn't support arrays-like iteration well, I wish to change 
> that and working on a proof of concept algorthims lib... but 
> well, this is unlikely to work.
>
> For d3 if changing the range interface fails, expect to see 
> style guides say "prefer explict range starters" 
> string.byUnicode and string.byAscii will probably be how they 
> kill `autodecoding` and your data stucture having 2 range 
> functions as `byKey` and `byKeyValue` will look the same.
>
>> Should I do an improvement request somewhere?
>
> I think its been kinda of piecemeal and D1 1D(repetition 
> intentional) opSlice is in limbo(it was deprecated, and then 
> slightly undepercated in some random chats, its a mess)
>
> for completeness I believe the current state of 1d op overloads 
> are:
>
> opIndex(int)
> opIndex(key)
> opSlice()
> opSlice(int, int)
> int opDollar()
> dollar opDollar()
> opSlice(int, dollar)
> opBinararyRight("in",K)(key) (opIn was deprecated and shouldn't 
> have been)
>
> If your confident in your writing ability id suggest a clean 
> slate article based on this list and what the compiler actually 
> does(maybe ask around for any I missed) rather than trying to 
> untangle this mess
>
> Or write a dip thread "undeperacate d1 opOverloads that are 
> still wanted by everyone") and try to bring back opIn at the 
> same time and get the limboness of old technically deprecated 
> 1d array opOverloads officially gone

I'm quite new to D yet. But I have some acquaintance with Python.
Therefore, together with templates the discovery of the Variant 
type was inspiring me to the following:
I wanted to explore if it's possible to do sort of type-agnostic 
programming with D. This could perhaps enable a simpler 
translation of Python code to D.

Trying with a `Variant[Variant] dct;` dictionary I observed that 
even simple assignment of key:value pairs was not possible as the 
different types are not automatically cast to a Variant.

Embedded in a struct with templating and casts to Variant such a 
dict now seems possible:

The preliminary code:

```d
// implement .get .update .require

import std.stdio;
import std.typecons;
import std.range;
import std.variant;
import std.string;
import std.format;

struct dict
{
	Variant[Variant] dct;

     Variant opIndex(T)(T key) {
		return dct[cast(Variant) key];
	}
     void opIndexAssign(V, T)(V val, T key) {
		dct[cast(Variant) key] = cast(Variant) val;
	}
	auto opBinaryRight(string op : "in", T)(T lhs) {
		return cast(Variant)lhs in dct;
	}
	@property auto keys() {
		return dct.keys;
	}
	@property auto values() {
		return dct.values;
	}
	auto remove(T)(T key) {
		return dct.remove(cast(Variant) key);
	}
	@property auto dup() {
		dict newd;
		foreach (k; dct.keys)  // do a deep copy
			newd.dct[k] = dct[k];
		return newd;
	}
	void toString(scope void delegate(const(char)[]) sink, 
FormatSpec!char fmt) {
		put(sink, "dict([");
		bool rep = false;
		foreach (k; dct.keys) {
			if (rep)
				put(sink, ", ");
			formatValue(sink, k, fmt);
			put(sink, ":");
			formatValue(sink, dct[k], fmt);
			rep = true;
		}
		put(sink, "])");
	}
	auto opSlice(){
		struct range{
			Variant[Variant]* parent;
			int i;
			auto front()=> tuple(parent.keys[i],(*parent)[parent.keys[i]]);
			auto popFront()=>i++;
			auto empty()=>parent.keys.length<=i;
		}
		return range(&this.dct);
	}
}

void main() {

	dict d;

	writeln("d: ", d);            // ==> dict([])
	writeln("d.keys: ", d.keys);
	writeln("d.values: ", d.values);
	writeln("d.keys.length: ", d.keys.length);
	writeln("------------");
	
	writeln("populating dict ....");
	d["hello"] = 2;
	d[3.1] = 5;
	d['c'] = 3.14;
	d[2] = "freak";
	d["mykey"] = 42;

	writeln("------------");
	
	writeln("d: ", d);            // ==> dict([2:0, mykey:42, 3.1:5, 
c:1, hello:2])
	writeln("d.keys: ", d.keys);
	writeln("d.values: ", d.values);
	writeln("d.keys.length: ", d.keys.length);
	writeln("------------");

	writeln(d["hello"], ", ", d[3.1], ", ", d['c'], ", ", d[2], ", 
", d["mykey"]);
	writeln("------------");
	
	d.remove("hello");
	writeln("\"hello\" in d:", "hello" in d);
	writeln("3.1 in d:", 3.1 in d);
	writeln("------------");
	foreach (key, value; d)                 // does not exhaust d
		writeln("key: ", key, "  value: ", value);
	writeln("------------");
	foreach (key, value; d)
		writeln("key: ", key, "  value: ", value);
	writeln("------------");
	auto d2 = d.dup;
	foreach (kv; d2)
		writeln("kv: ", kv);
}
```
Probably this is useless, but it was a nice challenge for 
learning.

> d2 Ranges are based on a simplification of stl's ideas and stl 
> doesn't support
> arrays-like iteration well, I wish to change that and working 
> on a proof of concept algorthims lib... but well, this is 
> unlikely to work.

> For d3 if changing the range interface fails, expect to see 
> style guides say "prefer explict range starters" 
> string.byUnicode and string.byAscii will probably be how they 
> kill autodecoding and your data stucture having 2 range 
> functions as byKey and byKeyValue will look the same.

I start to see that D is heavily influenced by C++ (STL), not 
just C.
This is not bad but might it make more difficult for people 
coming from other directions like Python to get acquainted with 
it.
Given that there are alternative developments like e.g. Mojo 
attempting to make Python to a transparently compiled language 
with C-like speed.

I was annoyed by C++'s complicated style from the beginning and 
am very happy now to have discovered D. Likewise it was with 
Markup/HTML and now I'm happy to see Markdown. Discussing with 
friends about this lead to: The complications (C++) were 
necessary perhaps to find a simple solution (D) in the end.
I cannot judge the range and similar concepts D now (not enough 
knowledge), but hope that the best combination of 
simplicity/clarity/might will prevail in future development.



More information about the Digitalmars-d-learn mailing list