Thread overview
Supporting foreach (k, v; T.init) for a user-defined (container) type
Oct 24, 2022
Per Nordlöw
Oct 24, 2022
rikki cattermole
Oct 24, 2022
H. S. Teoh
Oct 24, 2022
Ali Çehreli
Oct 25, 2022
Imperatorn
October 24, 2022

What property of a container (type) T enables iteration as

foreach (k, v; T.init)
{
    ...
}

? I thought it sufficed to define T.byKeyValue but its presence seem to have no effect.

October 25, 2022
From there down:

https://dlang.org/spec/statement.html#foreach_over_struct_and_classes
October 24, 2022
On Mon, Oct 24, 2022 at 09:26:14PM +0000, Per Nordlöw via Digitalmars-d-learn wrote:
> What property of a container (type) `T` enables iteration as
> 
> ```d
> foreach (k, v; T.init)
> {
>     ...
> }
> ```
> 
> ? I thought it sufficed to define `T.byKeyValue` but its presence seem to have no effect.

You want opApply.

Full working example:

------
struct A {
	static int[string] impl;
	static this() {
		impl = [
			"a": 1,
			"b": 2,
		];
	}

	int opApply(scope int delegate(string a, int b) dg) {
		foreach (k, v; impl) {
			auto r = dg(k, v);
			if (r) return r;
		}
		return 0;
	}
}

void main() {
	import std;
	A a;
	foreach (k, v; a) {
		writefln("%s -> %s", k, v);
	}
}
------


T

-- 
Computers shouldn't beep through the keyhole.
October 24, 2022
On 10/24/22 14:26, Per Nordlöw wrote:
> What property of a container (type) `T` enables iteration as
> 
> ```d
> foreach (k, v; T.init)
> {
>      ...
> }
> ```
> 
> ? I thought it sufficed to define `T.byKeyValue` but its presence seem to have no effect.

Another option is to use range functions where front() returns a Tuple. We have an esoteric feature where a tuple expands automatically in foreach loops:

import std.typecons : tuple;
import std.conv : to;
import std.stdio : writeln;
import std.range : take;

struct S {
    size_t count;
    bool empty = false;

    auto front() {
        const key = count;
        const value = key.to!string;
        return tuple(key, value);    // <-- HERE
    }

    void popFront() {
        ++count;
    }
}

void main() {
    foreach (k, v; S.init.take(10))
    {
        writeln(k, ": ", v);
    }
}

Ali

October 25, 2022
On Monday, 24 October 2022 at 21:52:18 UTC, Ali Çehreli wrote:
> On 10/24/22 14:26, Per Nordlöw wrote:
>> [...]
>
> Another option is to use range functions where front() returns a Tuple. We have an esoteric feature where a tuple expands automatically in foreach loops:
>
> import std.typecons : tuple;
> import std.conv : to;
> import std.stdio : writeln;
> import std.range : take;
>
> struct S {
>     size_t count;
>     bool empty = false;
>
>     auto front() {
>         const key = count;
>         const value = key.to!string;
>         return tuple(key, value);    // <-- HERE
>     }
>
>     void popFront() {
>         ++count;
>     }
> }
>
> void main() {
>     foreach (k, v; S.init.take(10))
>     {
>         writeln(k, ": ", v);
>     }
> }
>
> Ali

I didn't know about that esoteric feature. like this approach