digitalmars.D - More powerful foreach statements
- Ben Phillips (67/67) Jul 20 2006 While D's foreach is a much appreciated improvement over C++'s template ...
- kris (11/88) Jul 20 2006 Both can be done right now:
- Ben Phillips (9/18) Jul 20 2006 I remember seeing stuff like this in the MinTL code, but having to creat...
- Andrei Khropov (8/18) Jul 20 2006 And you can save you some typing if you like by omitting types:
- Oskar Linde (33/59) Jul 21 2006 Yes it does. Something like this:
- pragma (33/48) Jul 20 2006 Agreed. The only variation that is missing is for AA's:
- Oskar Linde (51/79) Jul 21 2006 or why not:
- Andrei Khropov (29/63) Jul 21 2006 Mmm, I would like slices to be first-class types and some synactic sugar...
- Oskar Linde (19/91) Jul 21 2006 Yes. A slice type would be extremely nice, and would also be needed to
- pragma (34/113) Jul 21 2006 Oh sure. If you want to do things the old-fashioned way... might as wel...
- Oskar Linde (28/89) Jul 21 2006 Yes, that is probably the right way do to it. If the views support the
- Kirk McDonald (9/18) Jul 21 2006 For what it's worth, writing a Python 'xrange'-style construct in D
While D's foreach is a much appreciated improvement over C++'s template version, I feel there are still some ways in which it can be improved. I listed two ideas below, though if you're in a hurry you can just skip to the second one because thats the most interesting one (imo). First proposal: an index tracker Recently there was a suggestion to allow "first" and "last" blocks in a foreach statement. This would allow things such as special initialization to get done during the first iteration through the foreach and possible clean-up work to get done during the last iteration. The current solution is to either go with a conventional "for" loop or to create a counter of some sort that counts what iteration the foreach statement is in (Though I'm not sure how one would detect the last iteration with a counter). It would convenient if a foreach statement automatically kept track of the iteration number. Example: foreach(Foo f; ManyFoos mf) { if (_iteration == 0) // special stuff on first iteration here .. } The _iteration variable should follow normal scoping rules so nested foreach statements can still access their own iteration counters. Second proposal: opApply variants This proposal is more radical than the last. One of the largest problems I have with foreach statements is that [afaik] iteration can only be done in one direction. For example, it is easy to use a foreach statement to iterate through an array starting at index zero but impossible to do it in reverse. The only way I know to work around this is the following: class Collection { private bool reverse = false; public Collection reverse() { // either sets reverse = true (therefore requiring it to get set back) or // duplicates this whole collection and sets the reverse flag in that one // (very expensive) } } I believe a possible solution to this would be to allow one to write different variants of opApply. Example: class Collection(T) { // normal opApply int opApply(int delegate(inout T) dg) { ... } // reverse order int opApply|reverse|(int delegate(inout T) dg) { ... } // some weird iteration pattern int opApply|weird|(int delegate(inout T) dg) { ... } } Usage: Collection!(int) collection = new Collection!(int)(); .. // to do a reverse order iteration foreach|reverse|(int element; collection) { ... } // a weird order one foreach|weird|(int element, collection) { ... } The idea is that within the function "opApply" there can be different variants that can created through use of another string placed inbetween pipe characters ("|"). This string can be whatever the class author feels is appropriate. This allows for easy implementation of different types of iteration that can be used with a foreach statement, while still allowing the compiler to recognize the "opApply" function. Technically the idea above could also be applied to other functions, however its usefulness degrades since most functions can just be renamed for different variants while opApply cannot.
Jul 20 2006
Ben Phillips wrote:While D's foreach is a much appreciated improvement over C++'s template version, I feel there are still some ways in which it can be improved. I listed two ideas below, though if you're in a hurry you can just skip to the second one because thats the most interesting one (imo). First proposal: an index tracker Recently there was a suggestion to allow "first" and "last" blocks in a foreach statement. This would allow things such as special initialization to get done during the first iteration through the foreach and possible clean-up work to get done during the last iteration. The current solution is to either go with a conventional "for" loop or to create a counter of some sort that counts what iteration the foreach statement is in (Though I'm not sure how one would detect the last iteration with a counter). It would convenient if a foreach statement automatically kept track of the iteration number. Example: foreach(Foo f; ManyFoos mf) { if (_iteration == 0) // special stuff on first iteration here .. } The _iteration variable should follow normal scoping rules so nested foreach statements can still access their own iteration counters. Second proposal: opApply variants This proposal is more radical than the last. One of the largest problems I have with foreach statements is that [afaik] iteration can only be done in one direction. For example, it is easy to use a foreach statement to iterate through an array starting at index zero but impossible to do it in reverse. The only way I know to work around this is the following: class Collection { private bool reverse = false; public Collection reverse() { // either sets reverse = true (therefore requiring it to get set back) or // duplicates this whole collection and sets the reverse flag in that one // (very expensive) } } I believe a possible solution to this would be to allow one to write different variants of opApply. Example: class Collection(T) { // normal opApply int opApply(int delegate(inout T) dg) { ... } // reverse order int opApply|reverse|(int delegate(inout T) dg) { ... } // some weird iteration pattern int opApply|weird|(int delegate(inout T) dg) { ... } } Usage: Collection!(int) collection = new Collection!(int)(); .. // to do a reverse order iteration foreach|reverse|(int element; collection) { ... } // a weird order one foreach|weird|(int element, collection) { ... } The idea is that within the function "opApply" there can be different variants that can created through use of another string placed inbetween pipe characters ("|"). This string can be whatever the class author feels is appropriate. This allows for easy implementation of different types of iteration that can be used with a foreach statement, while still allowing the compiler to recognize the "opApply" function. Technically the idea above could also be applied to other functions, however its usefulness degrades since most functions can just be renamed for different variants while opApply cannot.Both can be done right now: 1) foreach (int i, Foo f; ManyFooInstance) if (i is 0) .... Or somthing like that. 2) foreach (int element; collection.reverse) ... some kind of Iterator construct. IIRC, someone already has a framework for such things? Was it Oskar?
Jul 20 2006
In article <e9ogh7$b1b$1 digitaldaemon.com>, kris says...1) foreach (int i, Foo f; ManyFooInstance) if (i is 0) .... Or somthing like that.I tested it and it works, AND its documented. My fault.2) foreach (int element; collection.reverse) ... some kind of Iterator construct. IIRC, someone already has a framework for such things? Was it Oskar?I remember seeing stuff like this in the MinTL code, but having to create a separate type for each type of iteration that you want to support seems rather silly (though adding a new language feature to do so may be equally silly as well). Also, that still doesn't allow one to go reverse order through a builtin array with a foreach, unless of course you call ".reverse", which is needlessly expensive.
Jul 20 2006
Ben Phillips wrote:In article <e9ogh7$b1b$1 digitaldaemon.com>, kris says...And you can save you some typing if you like by omitting types: ------------------------------------------------------------------ foreach ( i,foo; ManyFooInstance) if (i is 0) ------------------------------------------------------------------ -- AKhropov1) foreach (int i, Foo f; ManyFooInstance) if (i is 0) .... Or somthing like that.I tested it and it works, AND its documented. My fault.
Jul 20 2006
Ben Phillips wrote:In article <e9ogh7$b1b$1 digitaldaemon.com>, kris says...Yes it does. Something like this: //Converts static arrays to dynamic arrays, leaving other types as //they are template MakeDynamic(T) { static if( is(typeof(Declare!(T).ptr[0]) E)) static if (is(T:E[])) alias E[] MakeDynamic; else alias T MakeDynamic; else alias T MakeDynamic; } struct ArrayReverseIterator(Array) { MakeDynamic!(Array) array; alias elementType!(Array) Element; int opApply(int delegate(inout Element) dg) { for (int i = array.length-1; i >= 0; i--) { if (auto status = dg(array[i])) return status; } return 0; } } ArrayReverseIterator!(Array) reverseIterator(Array)(Array array) { ArrayReverseIterator!(Array) iter; iter.array = array; return iter; } Usage: foreach(x; "abcd".reverseIterator()) writefln("x = %s",x); /Oskar1) foreach (int i, Foo f; ManyFooInstance) if (i is 0) .... Or somthing like that.I tested it and it works, AND its documented. My fault.2) foreach (int element; collection.reverse) ... some kind of Iterator construct. IIRC, someone already has a framework for such things? Was it Oskar?I remember seeing stuff like this in the MinTL code, but having to create a separate type for each type of iteration that you want to support seems rather silly (though adding a new language feature to do so may be equally silly as well). Also, that still doesn't allow one to go reverse order through a builtin array with a foreach, unless of course you call ".reverse", which is needlessly expensive.
Jul 21 2006
In article <e9ogh7$b1b$1 digitaldaemon.com>, kris says...Ben Phillips wrote:[snipped foreach proposal]While D's foreach is a much appreciated improvement over C++'s template version, I feel there are still some ways in which it can be improved. I listed two ideas below,Both can be done right now: 1) foreach (int i, Foo f; ManyFooInstance) if (i is 0) .... Or somthing like that.Agreed. The only variation that is missing is for AA's: foreach(key, value; myAA){ } Being able to get at the current iteration would be nice, but its certainly sugar. The only way I can see this single case being covered, is with a third foreach arg, like so: foreach(uint i,key,value; myAA){ } .. as this makes a rather nice, logical extension to things IMO. But I'm not holding my breath for its inclusion into D. ;) A variation would be to use a specialized iterator: uint i; foreach(key,value; myAA.forward(&i){ //i is incremented for each call of opApply() } .. or to iterate over the keys and lookup on each pass: foreach(i,key; myAA.keys){ auto value = myAA[key]; } I don't have a clue if doing an explicit lookup for 'value' is less efficent than letting the compiler figure it out what 'value' is via the foreach() expression. ::shrug::2) foreach (int element; collection.reverse) ... some kind of Iterator construct.Also agreed. There are simply too many kinds of variants for iteration, that anything outside the standard "storage order" (analagous to "database order" for SQL) iteration we have now should be left up to the developer. Granted, having a set of typical iterators like "reverse" would be a nice to have, but that's probably best left to a library.IIRC, someone already has a framework for such things? Was it Oskar?I remember seeing a heavily templated Array library posted here, that Andrew made a while back, could that be it? It was drafted well before implicit templates were available, so maybe its worth reviewing again. - EricAnderton at yahoo
Jul 20 2006
pragma wrote:In article <e9ogh7$b1b$1 digitaldaemon.com>, kris says...or why not: uint i = -1; foreach(key,value; myAA) { i++; ... } :)Ben Phillips wrote:[snipped foreach proposal] Being able to get at the current iteration would be nice, but its certainly sugar. The only way I can see this single case being covered, is with a third foreach arg, like so: foreach(uint i,key,value; myAA){ } .. as this makes a rather nice, logical extension to things IMO. But I'm not holding my breath for its inclusion into D. ;) A variation would be to use a specialized iterator: uint i; foreach(key,value; myAA.forward(&i){ //i is incremented for each call of opApply() }While D's foreach is a much appreciated improvement over C++'s template version, I feel there are still some ways in which it can be improved. I listed two ideas below,I also posted a templated array library suggestion earlier. It was drafted just after the inclusion of implicit function template instantiation and was designed to work with the current limited ifti support. The code would be a lot nicer if we got a more complete ifti support implemented though. The implementation and (ugly) ddoc: http://www.csc.kth.se/~ol/array.d http://www.csc.kth.se/~ol/array.html It doesn't currently contain any iterator functions. I've been toying with that a little though and have things like these working: // pensionCosts is 4 % of the net salary of employees older than 28 yrs // assume Employee[] employees; double pensionCosts = 0; foreach(e; employees.select((Employee e) { return e.age >= 28; })) pensionCosts += employee.salary * 0.04; Reverse iterators: (I haven't currently implemented reverse utf conversions, like foreach(dchar c; "abcd"c.reverseIterator()). It is a lot of work and I'm not sure they are worth it.) foreach(x; "abcd".reverseIterator()) writefln("x = %s",x); Python style ranges: foreach(x; range(5)) ... x is 0,1,2,3,4 foreach(x; range(1, 6)) ... x is 1,2,3,4,5 foreach(x; range(1.5, 0, -0.25)) // bad idea to support doubles? ... x is 1.5, 1.25, 1.0, 0.75, 0.5, 0.25 I've not found a good iterator design yet though. Only supporting foreach style iteration is a bit too limited. I would also like array views to work as iterators and also support common array operations without having to generate temporary arrays. Currently: double pensionCosts = employees .filter((Employee e) { return e.age >= 28; }) .map((Employee e) { return e.salary * 0.04; }) .sum(); Will generate a temporary Employee[] array and a temporary double[] array. Using array views one could get around the temporaries: // give all employees over 55 a 3 % raise: employees.select((Employee e) { return e.age >= 55; }) .update((Employee e) { e.salary *= 1.03; }); //(No temporaries created.) /OskarIIRC, someone already has a framework for such things? Was it Oskar?I remember seeing a heavily templated Array library posted here, that Andrew made a while back, could that be it? It was drafted well before implicit templates were available, so maybe its worth reviewing again.
Jul 21 2006
Oskar Linde wrote:Python style ranges: foreach(x; range(5)) ... x is 0,1,2,3,4 foreach(x; range(1, 6)) ... x is 1,2,3,4,5 foreach(x; range(1.5, 0, -0.25)) // bad idea to support doubles? ... x is 1.5, 1.25, 1.0, 0.75, 0.5, 0.25Mmm, I would like slices to be first-class types and some synactic sugar: ------------------------------------------------------- foreach(i; 0..5) ... i is 0,1,2,3,4 slice a = 1..5; int[5] arr = 0..5; // same as [0,1,2,3,4] foreach(x; arr[a]) ... x is arr[1], arr[2], ... arr[4] ------------------------------------------------------- But it's for D 1.0+ I think.I've not found a good iterator design yet though. Only supporting foreach style iteration is a bit too limited. I would also like array views to work as iterators and also support common array operations without having to generate temporary arrays.Yes, this is a definitely needed functionality.Currently: double pensionCosts = employees .filter((Employee e) { return e.age >= 28; }) .map((Employee e) { return e.salary * 0.04; }) .sum(); Will generate a temporary Employee[] array and a temporary double[] array. Using array views one could get around the temporaries: // give all employees over 55 a 3 % raise: employees.select((Employee e) { return e.age >= 55; }) .update((Employee e) { e.salary *= 1.03; }); //(No temporaries created.) /OskarSuch things should naturally belong to DTL I think. And I would also like to see type inference for delegate params by argument type in parameter declaration, e.g. : ------------------------------------------------------- employees.select( (e) { return e.age >= 55; }) .update( (e) { e.salary *= 1.03; }); ------------------------------------------------------- e is inferred to be Employee in both cases because select and update are declared as ------------------------------------------------------- ... select( delegate bool(Employee e) ) ... update( delegate void(Employee e) ) ------------------------------------------------------- if select is overloaded with different types then this would be ambiguous of course and we have to explicitly specify arg type. -- AKhropov
Jul 21 2006
Andrei Khropov wrote:Oskar Linde wrote:Yes. A slice type would be extremely nice, and would also be needed to support slicing of user defined multidimensional arrays. I would love to see opSlice(int start, int end) replaced with: opIndex(Range r); which would allow multidimensional mixed indexing and slicing like: arr[a..b, c, d..e, f..g, h, i]; via some template hackery. This could be implemented without breaking existing code by only calling opIndex(Range r) if no opSlice exists, so there is no rush to get this before D 1.0.Python style ranges: foreach(x; range(5)) ... x is 0,1,2,3,4 foreach(x; range(1, 6)) ... x is 1,2,3,4,5 foreach(x; range(1.5, 0, -0.25)) // bad idea to support doubles? ... x is 1.5, 1.25, 1.0, 0.75, 0.5, 0.25Mmm, I would like slices to be first-class types and some synactic sugar: ------------------------------------------------------- foreach(i; 0..5) ... i is 0,1,2,3,4 slice a = 1..5; int[5] arr = 0..5; // same as [0,1,2,3,4] foreach(x; arr[a]) ... x is arr[1], arr[2], ... arr[4] ------------------------------------------------------- But it's for D 1.0+ I think.Yeah. It's a pity D is so UDT hostile.I've not found a good iterator design yet though. Only supporting foreach style iteration is a bit too limited. I would also like array views to work as iterators and also support common array operations without having to generate temporary arrays.Yes, this is a definitely needed functionality.Currently: double pensionCosts = employees .filter((Employee e) { return e.age >= 28; }) .map((Employee e) { return e.salary * 0.04; }) .sum(); Will generate a temporary Employee[] array and a temporary double[] array. Using array views one could get around the temporaries: // give all employees over 55 a 3 % raise: employees.select((Employee e) { return e.age >= 55; }) .update((Employee e) { e.salary *= 1.03; }); //(No temporaries created.) /OskarSuch things should naturally belong to DTL I think.And I would also like to see type inference for delegate params by argument type in parameter declaration, e.g. : ------------------------------------------------------- employees.select( (e) { return e.age >= 55; }) .update( (e) { e.salary *= 1.03; }); ------------------------------------------------------- e is inferred to be Employee in both cases because select and update are declared as ------------------------------------------------------- ... select( delegate bool(Employee e) ) ... update( delegate void(Employee e) ) ------------------------------------------------------- if select is overloaded with different types then this would be ambiguous of course and we have to explicitly specify arg type.Yes, This makes D's delegates very close to Ruby's: {|e| e.salary = e.salary * 1.03 }. Exactly the same process of type inference exists already with foreach: foreach(x; myObj) // typeof(x) is inferred from the argument type of myObj.opApply() /Oskar
Jul 21 2006
In article <e9qe1i$1m5c$3 digitaldaemon.com>, Oskar Linde says...pragma wrote:Oh sure. If you want to do things the old-fashioned way... might as well use 'goto' while you're at it. ;pIn article <e9ogh7$b1b$1 digitaldaemon.com>, kris says...or why not: uint i = -1; foreach(key,value; myAA) { i++; ... } :)Ben Phillips wrote:[snipped foreach proposal] Being able to get at the current iteration would be nice, but its certainly sugar. The only way I can see this single case being covered, is with a third foreach arg, like so: foreach(uint i,key,value; myAA){ } .. as this makes a rather nice, logical extension to things IMO. But I'm not holding my breath for its inclusion into D. ;) A variation would be to use a specialized iterator: uint i; foreach(key,value; myAA.forward(&i){ //i is incremented for each call of opApply() }While D's foreach is a much appreciated improvement over C++'s template version, I feel there are still some ways in which it can be improved. I listed two ideas below,IMO, I think it's all *very* worth it. It kind of fills this gap between what phobos gives us and what STL's iterators and algorithms has to offer. I think that if you have an 'array view' widget/template that supports opApply(), length(), and opIndex() for all the view types you return, then you're pretty much set. That will cover both the random-access and sequential-access modes that arrays already enjoy. That way, you can support for() iteration as well, and still not need any temporaries. ;) As for ranges, I wouldn't throw those out. Ruby also has them, and thanks to Rails, prototype.js now supports them now too. I'd be willing to bet that someone will come along to the DNG and say "Where's the range support?!" - and we can all just point them to your library. I'd imagine ranges being an extension of your 'array view' concept. I think something like the following would be workable: /**/ struct ReverseArrayView(ArrayT){ /**/ ElemType!(ArrayT) opIndex(uint idx); /**/ ArrayT opSlice(uint start,uint end); //creates temporary or another view? /**/ int opApply(int delegate(inout ElemType!(ArrayT)) dg); /**/ uint length(); /**/ static opCall(ArrayT arr); /**/ } /**/ /**/ template reverse(ArrayT){ /**/ ReverseArrayView!(ArrayT) reverse(ArrayT arr){ /**/ return ReverseArrayView!(ArrayT)(arr); /**/ } /**/ } The trick is to get ArrayView instances to jive with your templates like ElemType!() such that they get treated like first-class arrays where possible. I think static if() could be used to check for a static property on ArrayViews like "isArrayView=true", such that standard arrays will fail the test. - EricAnderton at yahooI also posted a templated array library suggestion earlier. It was drafted just after the inclusion of implicit function template instantiation and was designed to work with the current limited ifti support. The code would be a lot nicer if we got a more complete ifti support implemented though. The implementation and (ugly) ddoc: http://www.csc.kth.se/~ol/array.d http://www.csc.kth.se/~ol/array.html It doesn't currently contain any iterator functions. I've been toying with that a little though and have things like these working: // pensionCosts is 4 % of the net salary of employees older than 28 yrs // assume Employee[] employees; double pensionCosts = 0; foreach(e; employees.select((Employee e) { return e.age >= 28; })) pensionCosts += employee.salary * 0.04; Reverse iterators: (I haven't currently implemented reverse utf conversions, like foreach(dchar c; "abcd"c.reverseIterator()). It is a lot of work and I'm not sure they are worth it.) foreach(x; "abcd".reverseIterator()) writefln("x = %s",x); Python style ranges: foreach(x; range(5)) ... x is 0,1,2,3,4 foreach(x; range(1, 6)) ... x is 1,2,3,4,5 foreach(x; range(1.5, 0, -0.25)) // bad idea to support doubles? ... x is 1.5, 1.25, 1.0, 0.75, 0.5, 0.25 I've not found a good iterator design yet though. Only supporting foreach style iteration is a bit too limited. I would also like array views to work as iterators and also support common array operations without having to generate temporary arrays. Currently: double pensionCosts = employees .filter((Employee e) { return e.age >= 28; }) .map((Employee e) { return e.salary * 0.04; }) .sum(); Will generate a temporary Employee[] array and a temporary double[] array. Using array views one could get around the temporaries: // give all employees over 55 a 3 % raise: employees.select((Employee e) { return e.age >= 55; }) .update((Employee e) { e.salary *= 1.03; }); //(No temporaries created.) /OskarIIRC, someone already has a framework for such things? Was it Oskar?I remember seeing a heavily templated Array library posted here, that Andrew made a while back, could that be it? It was drafted well before implicit templates were available, so maybe its worth reviewing again.
Jul 21 2006
pragma wrote:In article <e9qe1i$1m5c$3 digitaldaemon.com>, Oskar Linde says...Yes, that is probably the right way do to it. If the views support the same operations as arrays do, they will be usable just as arrays, and views-of-views and similar would work transparently.I've not found a good iterator design yet though. Only supporting foreach style iteration is a bit too limited. I would also like array views to work as iterators and also support common array operations without having to generate temporary arrays. Currently: double pensionCosts = employees .filter((Employee e) { return e.age >= 28; }) .map((Employee e) { return e.salary * 0.04; }) .sum(); Will generate a temporary Employee[] array and a temporary double[] array. Using array views one could get around the temporaries: // give all employees over 55 a 3 % raise: employees.select((Employee e) { return e.age >= 55; }) .update((Employee e) { e.salary *= 1.03; }); //(No temporaries created.) /OskarIMO, I think it's all *very* worth it. It kind of fills this gap between what phobos gives us and what STL's iterators and algorithms has to offer. I think that if you have an 'array view' widget/template that supports opApply(), length(), and opIndex() for all the view types you return, then you're pretty much set. That will cover both the random-access and sequential-access modes that arrays already enjoy. That way, you can support for() iteration as well, and still not need any temporaries. ;)As for ranges, I wouldn't throw those out. Ruby also has them, and thanks to Rails, prototype.js now supports them now too. I'd be willing to bet that someone will come along to the DNG and say "Where's the range support?!" - and we can all just point them to your library. I'd imagine ranges being an extension of your 'array view' concept.Yes, ideally, a range should work just like a (read only) array, but without allocating any memory. Silly example: range(100).select((int x) { return x % 5 == 0 }).sum() //returns 950I think something like the following would be workable: /**/ struct ReverseArrayView(ArrayT){ /**/ ElemType!(ArrayT) opIndex(uint idx); /**/ ArrayT opSlice(uint start,uint end); //creates temporary or another view? /**/ int opApply(int delegate(inout ElemType!(ArrayT)) dg); /**/ uint length(); /**/ static opCall(ArrayT arr); /**/ } /**/ /**/ template reverse(ArrayT){ /**/ ReverseArrayView!(ArrayT) reverse(ArrayT arr){ /**/ return ReverseArrayView!(ArrayT)(arr); /**/ } /**/ } The trick is to get ArrayView instances to jive with your templates like ElemType!() such that they get treated like first-class arrays where possible. I think static if() could be used to check for a static property on ArrayViews like "isArrayView=true", such that standard arrays will fail the test.Yes, that is definitely doable. The only problem is that there is no way to "inject" methods for anything but built-in arrays. I'd have to add wrappers to all views for all functions (a mixin will probably be enough), or live with calling them as ordinary functions: update(select(employees, (Employee e) { return e.age >= 55; }), (Employee e) { e.salary *= 1.03; }); instead of: employees.select((Employee e) { return e.age >= 55; }) .update((Employee e) { e.salary *= 1.03; }); It would be nice to have a way to inject methods/define extension methods for other types than arrays. Maybe something like what has been proposed before: int squared(this int x) { return x*x; } and called: 5.squared(); Just add ifti template support to this and the array functions would be applicable as methods of any type that implements the needed iterator semantics (opApply or opIndex and length()). /Oskar
Jul 21 2006
Oskar Linde wrote:Python style ranges: foreach(x; range(5)) ... x is 0,1,2,3,4 foreach(x; range(1, 6)) ... x is 1,2,3,4,5 foreach(x; range(1.5, 0, -0.25)) // bad idea to support doubles? ... x is 1.5, 1.25, 1.0, 0.75, 0.5, 0.25For what it's worth, writing a Python 'xrange'-style construct in D isn't that hard. I've posted one previously to the group: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/38808 Some follow-ups to that post had templated versions. -- Kirk McDonald Pyd: Wrapping Python with D http://dsource.org/projects/pyd/wiki
Jul 21 2006