extending foreach for keyed ranges and other usage of datastructures

monkyyy crazymonkyyy at gmail.com
Wed May 15 20:27:12 UTC 2024


extend the api of foreach to allow for `foreach(key,value;data)` 
for user data types,
  and user defined "autodecoding"

### related debates

the (unnesery) deperacation of "implict casts" of array indexes 
to int 
https://forum.dlang.org/thread/qdsypzjwptbebffktohx@forum.dlang.org

key'd ranges in general 
https://forum.dlang.org/thread/akczwyrmlpocihmaitbz@forum.dlang.org

### definitions

keyd range: a struct that defines the functions 
front,popFront,empty and key

autodecoding: when a data structure is implicitly transformed 
into a range by a imported function and ufcs (not string specific)

foreach header: the part of the foreach call that comes before 
the ;


### priority

1. if the template header and data combo are currently valid, 
dont change behavior(whatever that looks like)

2. if the data is a keyd range but the foreach header has a key; 
define key to be range.key and value to be range.front; handle 
ref if possible

3. if data is not a range, attempt to call opSlice to see if 
thats a range (static arrays)

4. if data does not have an opSlice, "autodecode" 
`data.toRange!(details from foreach header)`

### foreach header parsing

because ref isnt on types I dont believe you can pass "ref int" 
into a template, and maybe theres something about named 
arguments, I believe this should be handled with strings.

unattributed arguments are replaced with void, so the user can 
handle hard cases tuples as they wish(2d iteration, or zipped 
ranges)

`foreach(int k,value:ref @safe v;...)` would be parsed as 
("int","value:ref @safe") Im unsure what user code does with 
"@safe" but let the user figure it out

`foreach(a,b,c,d,e,f,g;...)` would be parsed as 
(void,void,void,void,void,void)

### keyd range example code

```d
struct strangecounter{
   int front;
   int last;
   void popFront(){front++;}
   int key()=>front*front;
   bool empty()=> last>=front;
}
foreach(k,v;strangecounter(0,10)){
   writeln(k,":",v);//0:0, 1:1, 4:2,9:3.....
}
```

`foreach(ref k,v;strangecounter(0,10))` would fail to compile, 
some complaint about lvalues or suggesting the user to define a 
`torange!("ref",void)`
`foreach(k,ref v;strangecounter(0,10))` would compile
`foreach(size_t k,v;strangecounter(0,10))` would fail to compile, 
suggesting the user to define a `torange!("size_t",void)`
`foreach(a,b,c;strangecounter(0,10))` would fail to compile, and 
suggesting the user define a torange!(void,void,void)
`foreach(v;strangecounter(0,10))` would compile (using keys are 
optional)

### torange example code

handling int indexing

```d
auto torange(string s:"int",T)(ref T[] array){
   struct myrange{
     int key_;
     auto key()=>key_;//unref's key
     auto front()=>array[key];
     auto popFront(){key_++;}
     auto empty()=>arra.length>=key;
   }
   return myrange;
}
foreach(int i,v;array){//compiles
```



More information about the dip.ideas mailing list