digitalmars.D.bugs - [Issue 2543] New: foreach's index behaves differently for every type
- d-bugmail puremagic.com (89/89) Dec 27 2008 http://d.puremagic.com/issues/show_bug.cgi?id=2543
- d-bugmail puremagic.com (9/9) Jan 22 2012 http://d.puremagic.com/issues/show_bug.cgi?id=2543
- d-bugmail puremagic.com (12/12) Nov 01 2013 http://d.puremagic.com/issues/show_bug.cgi?id=2543
http://d.puremagic.com/issues/show_bug.cgi?id=2543 Summary: foreach's index behaves differently for every type Product: D Version: 2.022 Platform: PC OS/Version: Linux Status: NEW Keywords: diagnostic, spec Severity: minor Priority: P2 Component: DMD AssignedTo: bugzilla digitalmars.com ReportedBy: lat7h virginia.edu The behavior of foreach index differs depending on what type of thing is being iterated. * For static and dynamic arrays, index cannot be ref but always acts like it is ref. * For associative arrays, index cannot be ref and always act accordingly. * For structs and classes, index can be either ref or non-ref,and behaves accordingly. However, ref behavior cannot be blocked it undesirable. While the current system works, it is needlessly inconsistent. The full behavior is exposed by the following example: ---- void plain(T)(T iterable) { foreach (i, v; iterable) write(i++," "); } void refer(T)(T iterable) { foreach (ref i, v; iterable) write(i++," "); } struct allow_ref { int opApply(int delegate(inout uint, inout int) dg) { int res; for (uint i=0; i<4; ++i) res = dg(i,i+1); return res; } } struct ignore_ref { int opApply(int delegate(inout uint, inout int) dg) { int res; for (uint i=0; i<4; ++i) res = dg(i+0,i+1); return res; } } struct fail_on_write { int opApply(int delegate(inout const(uint), inout int) dg) { int res; for (uint i=0; i<4; ++i) res = dg(i,i+1); return res; } } void main(string[] args) { int[] array = [1,2,3,4]; // int[4] behaves the same plain(array); // OK: "0 2" refer(array); // Error: foreach: key cannot be out or ref int[int] assoc = [0:1,1:2,2:3,3:4]; plain(assoc); // OK: "0 1 2 3" refer(assoc); // Error: foreach: index cannot be ref allow_ref custom1; plain(custom1); // OK: "0 1 2 3" refer(custom1); // OK: "0 2" ignore_ref custom2; plain(custom2); // OK: "0 1 2 3" refer(custom2); // OK: "0 1 2 3" fail_on_write custom3; plain(custom3); // Error: plain.foreachbody23.index cannot modify const refer(custom3); // Error: refer.foreachbody23.index cannot modify const } ---- A minor note: int[] calls the index "key"; int[int] calls it "index". These are either inconsistent or backward. Also, foreach can't have out-qualified elements, so the "out or" in the array error message seems odd. If I want to build something like an associative array, where the index type is mutable but the index itself cannot be modified to control the iteration, no good solution exists: * making the delegate not accept ref input fails to match foreach call * making the index const prevents even local modifications * making the index tamper-proof fails to let the user know what is happening I propose at least the following simple fixes: * foreach(i,v; array) should have "i" not control iteration * foreach(ref i,v; array) should be allowed and have the behavior currently exhibited by foreach(i,v; array) behavior Preventing foreach(ref i,v; structOrClass) is less obvious. Some possibilities: * non-ref foreach loops search first for non-ref delegates, falling back on a ref delegate is they are not available. This keeps the benefit of being albe to write a single method for all four ref/nonref cases and allows the programmer to rule out certain ref usages at compile time. I have no idea how difficult it would be to implement. While we're at it, I'd love to see the two-parameter delegate opApply used in lieu of one-parameter if the later is lacking... * non-ref foreach currently uses ref delegates without propagating writes back into the opApply body; if this implicit copy removed the const() (where allowed by the typing rules) the fail_on_write struct would work (for some index types). * each of the six foreach types (v;A) (ref v;A) (i,v;A) (ref i,v;A) (i,ref v;A) (ref i, ref v;A) could create a different delegate signature, so that a fully foreach-enabled struct has six more-or-less identical opApply methods with slightly different parameters. --
Dec 27 2008
http://d.puremagic.com/issues/show_bug.cgi?id=2543 Walter Bright <bugzilla digitalmars.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |bugzilla digitalmars.com Severity|minor |enhancement -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 22 2012
http://d.puremagic.com/issues/show_bug.cgi?id=2543 Martin Nowak <code dawg.eu> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|NEW |RESOLVED CC| |code dawg.eu Resolution| |DUPLICATE *** This issue has been marked as a duplicate of issue 6652 *** -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Nov 01 2013