digitalmars.D - range methods on associative arrays
- WebFreak001 (21/21) Jul 02 2022 a lot of range methods, such as `filter`, `any`, `all`, `count`,
- Steven Schveighoffer (6/31) Jul 02 2022 This idea misunderstands what a range is.
- WebFreak001 (7/44) Jul 02 2022 arrays/slices are also not ranges and get special-cased (or at
- Steven Schveighoffer (6/19) Jul 02 2022 arrays/slices are ranges. They are actually the essential range type.
- Paul Backus (14/17) Jul 02 2022 To be fair this is also true of some ranges.
- Steven Schveighoffer (10/29) Jul 02 2022 Right, but by default iterating an AA doesn't do this, and nobody would
- monkyyy (36/37) Jul 02 2022 Its a general problem that ranges are bad are mimicking some
- bauss (7/31) Jul 03 2022 I think this confuses an associative array/hashmap with a "list"
a lot of range methods, such as `filter`, `any`, `all`, `count`, `each`, etc. would be useful on associative arrays, taking in key and value, returning a processed .byKeyValue range. I would suggest, at least for phobos v2, we should have these functions automatically call `.byKeyValue` on maps and there should be support for lambdas with 2 arguments there, which automatically unwrap key and value (and possibly all tuples actually) What do you think? ```d map.each!((key, value) { /* like a foreach, but functional style */ }); bool hasId = map.any!((key, value) => key == "id" && value !is null); ``` for this I think the implementation would basically boil down to: - implicitly call `.byKeyValue` in the map-accepting range methods - allow tuples and the KeyValue pair to be extended into multiple parameters on CT lambdas that have multiple arguments Users wanting to only use keys or only values can still use .byKey or .byValue.
Jul 02 2022
On 7/2/22 4:14 PM, WebFreak001 wrote:a lot of range methods, such as `filter`, `any`, `all`, `count`, `each`, etc. would be useful on associative arrays, taking in key and value, returning a processed .byKeyValue range. I would suggest, at least for phobos v2, we should have these functions automatically call `.byKeyValue` on maps and there should be support for lambdas with 2 arguments there, which automatically unwrap key and value (and possibly all tuples actually) What do you think? ```d map.each!((key, value) { /* like a foreach, but functional style */ }); bool hasId = map.any!((key, value) => key == "id" && value !is null); ``` for this I think the implementation would basically boil down to: - implicitly call `.byKeyValue` in the map-accepting range methods - allow tuples and the KeyValue pair to be extended into multiple parameters on CT lambdas that have multiple arguments Users wanting to only use keys or only values can still use .byKey or .byValue.This idea misunderstands what a range is. In order for an AA to be considered a "range", each popFront should remove the element from the AA. We don't want that. Just use the range accessors. -Steve
Jul 02 2022
On Saturday, 2 July 2022 at 21:18:06 UTC, Steven Schveighoffer wrote:On 7/2/22 4:14 PM, WebFreak001 wrote:arrays/slices are also not ranges and get special-cased (or at least have compatibility functions in std.range.primitives) to be used with range code, I don't see any reason why not to do this with maps as well, which are a first class feature of the language.a lot of range methods, such as `filter`, `any`, `all`, `count`, `each`, etc. would be useful on associative arrays, taking in key and value, returning a processed .byKeyValue range. I would suggest, at least for phobos v2, we should have these functions automatically call `.byKeyValue` on maps and there should be support for lambdas with 2 arguments there, which automatically unwrap key and value (and possibly all tuples actually) What do you think? ```d map.each!((key, value) { /* like a foreach, but functional style */ }); bool hasId = map.any!((key, value) => key == "id" && value !is null); ``` for this I think the implementation would basically boil down to: - implicitly call `.byKeyValue` in the map-accepting range methods - allow tuples and the KeyValue pair to be extended into multiple parameters on CT lambdas that have multiple arguments Users wanting to only use keys or only values can still use .byKey or .byValue.This idea misunderstands what a range is. In order for an AA to be considered a "range", each popFront should remove the element from the AA. We don't want that. Just use the range accessors. -Steve
Jul 02 2022
On 7/2/22 5:51 PM, WebFreak001 wrote:On Saturday, 2 July 2022 at 21:18:06 UTC, Steven Schveighoffer wrote:arrays/slices are ranges. They are actually the essential range type. Also, an AA is fundamentally different. I can popFront on a slice, and it doesn't affect other slices. If I popFront an element from an AA, it affects all other references to that AA. -SteveThis idea misunderstands what a range is. In order for an AA to be considered a "range", each popFront should remove the element from the AA. We don't want that. Just use the range accessors.arrays/slices are also not ranges and get special-cased (or at least have compatibility functions in std.range.primitives) to be used with range code, I don't see any reason why not to do this with maps as well, which are a first class feature of the language.
Jul 02 2022
On Saturday, 2 July 2022 at 23:13:43 UTC, Steven Schveighoffer wrote:Also, an AA is fundamentally different. I can popFront on a slice, and it doesn't affect other slices. If I popFront an element from an AA, it affects all other references to that AA.To be fair this is also true of some ranges. The real usability issue here is that if AAs a ranges with reference semantics, then code like this ```d auto aa = ["foo": 123, "bar": 456]; foreach (key, val; aa) doSomethingWith(key, val); ``` ...will consume the range, leaving `aa` empty after the loop completes. So most of the time, you will want to use `.byKeyValue` anyway, even if AAs implement the range interface "natively."
Jul 02 2022
On 7/2/22 7:53 PM, Paul Backus wrote:On Saturday, 2 July 2022 at 23:13:43 UTC, Steven Schveighoffer wrote:Right, but by default iterating an AA doesn't do this, and nobody would expect it.Also, an AA is fundamentally different. I can popFront on a slice, and it doesn't affect other slices. If I popFront an element from an AA, it affects all other references to that AA.To be fair this is also true of some ranges.The real usability issue here is that if AAs a ranges with reference semantics, then code like this ```d auto aa = ["foo": 123, "bar": 456]; foreach (key, val; aa) doSomethingWith(key, val); ``` ...will consume the range, leaving `aa` empty after the loop completes. So most of the time, you will want to use `.byKeyValue` anyway, even if AAs implement the range interface "natively."Technically, this doesn't use the range API. However, aa.map!(...) would, and that's where the real problems would begin. The proposal is somewhat cleverer in that it will implicitly call `byKeyValue`, but this I don't think scales well, unless the compiler is made to do it. I think saving the call to `.byKeyValue` isn't worth this trouble. -Steve
Jul 02 2022
On Saturday, 2 July 2022 at 20:14:10 UTC, WebFreak001 wrote:make more special cases like auto decodingIts a general problem that ranges are bad are mimicking some types of for loop patterns; not a specific one ```d foreach(e;list){ if(e.foo==cond){break;} e.bar; } //if foo is local, it may not scope correctly into std.filter`s lamda ``` ```d auto store; foreach(ref e;list){ e=foo(e,store); store=bar(e,store); e.foobar; } ``` one could argue that there are 4 useful data structures that come out of the box, static arrays, slices, strings, and aa's and that the benefit of templates is that you get (in theory) great implications when combining non-specialized data structures and algorithms; and you would be in effect suggesting the std increases its special cases to 2 out of 4. (If not 3 with slices and gc) I suggest that aa's should follow the rough standard syntax that is the best I can mimic of defining `[]` to return a range for my data structures instead of the verbose thing I always have to look up. And that the algorithms the std define are robust enough to handle the general problems. Fundamentally the std is written as if caring that ranges should be reference types; I dislike that take, but you'd be fighting an uphill battle to suggest it changes on a real level. And your suggestion would make the same sort of hacks that string has and the issues that follow.
Jul 02 2022
On Saturday, 2 July 2022 at 20:14:10 UTC, WebFreak001 wrote:a lot of range methods, such as `filter`, `any`, `all`, `count`, `each`, etc. would be useful on associative arrays, taking in key and value, returning a processed .byKeyValue range. I would suggest, at least for phobos v2, we should have these functions automatically call `.byKeyValue` on maps and there should be support for lambdas with 2 arguments there, which automatically unwrap key and value (and possibly all tuples actually) What do you think? ```d map.each!((key, value) { /* like a foreach, but functional style */ }); bool hasId = map.any!((key, value) => key == "id" && value !is null); ``` for this I think the implementation would basically boil down to: - implicitly call `.byKeyValue` in the map-accepting range methods - allow tuples and the KeyValue pair to be extended into multiple parameters on CT lambdas that have multiple arguments Users wanting to only use keys or only values can still use .byKey or .byValue.I think this confuses an associative array/hashmap with a "list" of key-value pairs; which isn't the same. An associative array isn't really range-like in nature, if it was up to me then you shouldn't even be able to natively iterate over it in a foreach like you can now, but that's just me being too strict for the norm I guess.
Jul 03 2022