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

2024-03-13 Thread rkompass via Digitalmars-d-learn
I want to make a custom dictionary that I may iterate through 
with foreach. Several times.
What I observe so far is that my dict as a simple forward range 
is exhausted after the first foreach and I have to deeply copy it 
beforehand.

With a simple associative array the exhaustion is not observed.
Is there a (hopefully simple) way to make this 
automatic/transparent? Of course

I need to use the struct.
Can I add a save member function? If yes: How? Or is there an 
operator that is used in the foreach initialization that I may 
overload in this struct?


My code:
```d
import std.stdio;
import std.string;
import std.typecons;

struct mydict {
   string[string] dct;

   @property bool empty() const {
  return dct.empty;
   }
   @property ref auto front() {
  return tuple(dct.keys[0], dct[dct.keys[0]]);
   }
void popFront() {
dct.remove(dct.keys[0]);
}
void opAssign(mydict rhs) {
writeln("--opAssign--");
foreach (k; rhs.dct.keys)  // do a deep copy
dct[k] = rhs.dct[k];
}
}

void main() {

mydict md, md2;
md.dct = ["h":"no", "d":"ex", "r": "cow"];
md2 = md; // md2.opAssign(md)
foreach (k, v; md)
writeln("key: ", k, "val: ", v);
writeln("--");
	foreach (k, v; md)   // does not work with md again, md is 
exhausted

writeln("key: ", k, "val: ", v);
}
```


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

2024-03-14 Thread monkyyy via Digitalmars-d-learn

On Wednesday, 13 March 2024 at 22:16:52 UTC, rkompass wrote:
I want to make a custom dictionary that I may iterate through 
with foreach. Several times.
What I observe so far is that my dict as a simple forward range 
is exhausted after the first foreach and I have to deeply copy 
it beforehand.

With a simple associative array the exhaustion is not observed.
Is there a (hopefully simple) way to make this 
automatic/transparent? Of course

I need to use the struct.
Can I add a save member function? If yes: How? Or is there an 
operator that is used in the foreach initialization that I may 
overload in this struct?


you need to seperate the range state from the data

```d
import std;
auto tuple(T...)(T t){
struct tuple{
T me; alias me this;
}
return tuple(t);
}
struct mydict(T,S){
T[S] dct;
void opAssign(mydict rhs) {
writeln("--opAssign--");
foreach (k; rhs.dct.keys)  // do a deep copy
dct[k] = rhs.dct[k];
}
auto opSlice(){
struct range{
T[S]* 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() {

mydict!(string,string) md, md2;
md.dct = ["h":"no", "d":"ex", "r": "cow"];
md2 = md; // md2.opAssign(md)
foreach (k, v; md[])
writeln("key: ", k, "val: ", v);
writeln("--");
	foreach (k, v; md[])   // does not work with md again, md is 
exhausted

writeln("key: ", k, "val: ", v);
}
```


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

2024-03-14 Thread rkompass via Digitalmars-d-learn

Hello @monkyyy,

thank you for your help. I will study and try your code.

Meanwhile I have found that I can add this function into the 
struct:


```d
// postblit constructor, see
// 
https://stackoverflow.com/questions/38785624/d-struct-copy-constructor

this(this) {
string[string] ndct;
foreach (k; dct.keys)  // do a deep copy
ndct[k] = dct[k];
dct = ndct;
}
```



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

2024-03-14 Thread Monkyyy via Digitalmars-d-learn

On Thursday, 14 March 2024 at 16:32:10 UTC, rkompass wrote:

On Thursday, 14 March 2024 at 16:12:00 UTC, rkompass wrote:
Hello @monkyyy again,

your solution is much more elegant:-) No need to do a deep copy.
I was thinking about a way to achieve that but had no clue.

I will study opSlice now.

Your definition of tuple is somewhat obscure to me.
Is this compatible with the Tuple from `std.typecons`?

Greetings,
Raul


Std.tuple is a gaint mess if there's differences in usage syntax 
they are very stupid tradeoffs; fundementally the base languge 
has allot of syntax sugar for "aliasSeq" and my definition of 
tuple is sticking an Seq into a struct; if you look at the code 
for std.tuple it will do the same thing under the name "expand"


If you go down the rabbit hole of learning the template syntax 
you should start with the systax aviable for seq's and 95% of it 
will apply to that definition of tuple


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

2024-03-15 Thread rkompass via Digitalmars-d-learn

@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.


Can this somehow be detected by the opSlice or is there another 
overloading

construct to be applied for this?


Addition: I noted that in the best matching 
[docs](https://dlang.org/spec/operatoroverloading.html#slice) 
only *ordinary arrays* are covered. Your solution would make a 
very nice addition for the case of associative arrays there. I 
learn't a lot from it.

Should I do an improvement request somewhere?





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

2024-03-15 Thread monkyyy via Digitalmars-d-learn

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


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

2024-03-15 Thread rkompass via Digitalmars-d-learn

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"] =

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

2024-03-15 Thread bachmeier via Digitalmars-d-learn

On Friday, 15 March 2024 at 20:36:56 UTC, rkompass wrote:

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.


You're not the first one. There's no technical reason for the 
restriction. It's simply a matter of being opposed by those who 
make these decisions on the basis that it's the wrong way to 
program or something like that. Here is a recent thread: 
https://forum.dlang.org/post/ikwphfwevgnsxmdfq...@forum.dlang.org


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

2024-03-16 Thread monkyyy via Digitalmars-d-learn

On Friday, 15 March 2024 at 20:36:56 UTC, rkompass wrote:


I start to see that D is heavily influenced by C++ (STL), not 
just C.

This is not bad



It is just bad; ranges are not pairs of 2 pointers, stepov was 
comprising with c++ or if he thinks c++ iterators are objectively 
good(not good for making something work with c++) he's lacks taste


even simplified a "random access range" is to complex an 
api(close to 20 functions) when Im pretty sure you need 6 
functions for a coherent array-like interface and when your 
talking about 100 algorthims, well 1400 functions matters


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

2024-03-18 Thread rkompass via Digitalmars-d-learn
To solve the problem with the 1-variable and 2-variable versions 
of foreach I
tried opApply and found that the compiler prefers it over opSlice 
and opIndex() (the latter without argument).


My code:

```d
int opApply(int delegate(Variant) foreachblock) const {
int result = 0;
foreach(val; dct) {
result = foreachblock(val);
if (result)
break;
}
return result;
}
int opApply(int delegate(Variant, Variant) foreachblock) const {
int result = 0;
foreach(key, val; dct) {
result = foreachblock(key, val);
if (result)
break;
}
return result;
}
```
So I'm fine with this now.




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

2024-03-18 Thread rkompass via Digitalmars-d-learn

@bachmeier
You're not the first one. There's no technical reason for the 
restriction. It's simply a matter of being opposed by those who 
make these decisions on the basis that it's the wrong way to 
program or something like that. Here is a recent thread: 
https://forum.dlang.org/post/ikwphfwevgnsxmdfq...@forum.dlang.org


Thank you for this. Very interesting discussion. And apparently a 
deliberate restriction of flexibility in type conversion.


I will first try to understand better how templates work under 
the hood before joining this discussion.


Given the types S and T in say `templfunc(S, T)(S arg1, T arg2) 
{}`
represent 2 different actual types in the program, does that mean 
that there are 4 versions of the `templfunc` function compiled 
in? (This was the C++ way iirc).
Or are the types T and S are put on the stack like ordinary 
arguments and the usage of arg1 and arg2 within the function is 
enveloped in switches that query these Types?




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

2024-03-18 Thread novice2 via Digitalmars-d-learn

On Monday, 18 March 2024 at 08:50:42 UTC, rkompass wrote:
Given the types S and T in say `templfunc(S, T)(S arg1, T arg2) 
{}`
represent 2 different actual types in the program, does that 
mean that there are 4 versions of the `templfunc` function 
compiled in? (This was the C++ way iirc).


IMHO, only if you instantiate (make call) templfunc with all 
types.



Or are the types T and S are put on the stack like ordinary 
arguments and the usage of arg1 and arg2 within the function is 
enveloped in switches that query these Types?


IMHO, only if you instantiate (make call) templfunc, then 
compiler create function with specified types.

Function created only once for given types combination.


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

2024-03-18 Thread novice2 via Digitalmars-d-learn

On Monday, 18 March 2024 at 10:05:43 UTC, novice2 wrote:

On Monday, 18 March 2024 at 08:50:42 UTC, rkompass wrote:
Or are the types T and S are put on the stack like ordinary 
arguments and the usage of arg1 and arg2 within the function 
is enveloped in switches that query these Types?


IMHO, only if you instantiate (make call) templfunc, then 
compiler create function with specified types.

Function created only once for given types combination.


this also can be helpfull:
https://dlang.org/spec/template.html#common_instantiation