October 24, 2006 Re: foreach, an analogy | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley | Jarrett Billingsley wrote: > "Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message news:eh6rva$1anj$2@digitaldaemon.com... > > >>I think it may be Ruby blocks. > > > They're just anonymous functions which happen to come after the function call's closing paren.. I wouldn't really say that they're incredibly earth-shattering or the answer to everything. And D can almost do them already. Instead of: > > something.each do |item| > puts item > end > > You can have: > > something.each((int item) { > writefln(item); > }); > > In fact the "allowing a trailing function literal" has been proposed (by myself included), which would allow: > > something.each()(int item) > { > writefln(item); > } You know, personally I prefer the first way to do it than the second, it's "more orthogonal/clean". I wonder why it's not used more? It seems quite readable, maybe there is a performance impact (shouldn't happen if the compiler inline the each function call). Of course both ways are a little more verbose than Ruby due to the static typing, but they are still very good. I wonder if with templates there couldn't be a way to have the "item" element declared implicitely with the correct type? Regards, renoX > // maybe there'd need to be a semicolon here? > > Which is damn close if you ask me. > > |
October 25, 2006 Re: foreach, an analogy | ||||
---|---|---|---|---|
| ||||
Posted in reply to renox | renox wrote: > Jarrett Billingsley wrote: > >> "Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message news:eh6rva$1anj$2@digitaldaemon.com... >> >> >>> I think it may be Ruby blocks. >> >> >> They're just anonymous functions which happen to come after the function call's closing paren.. I wouldn't really say that they're incredibly earth-shattering or the answer to everything. And D can almost do them already. Instead of: >> >> something.each do |item| >> puts item >> end >> >> You can have: >> >> something.each((int item) { >> writefln(item); >> }); >> >> In fact the "allowing a trailing function literal" has been proposed (by myself included), which would allow: >> >> something.each()(int item) >> { >> writefln(item); >> } > > You know, personally I prefer the first way to do it than the second, it's "more orthogonal/clean". To each his own. I don't think version 1 would be made illegal or anything if the trailing delegate proposal were implemented. But the main difference between them is that version 1 doesn't handle labeled break or goto from within the delegate. Version 2 would presumably rewrite the delegate literal in the same way 'foreach' does now. On the other hand, version 1 works perfectly well with non-literal delegates too, and I don't see version 2 ever being made to work that way. something.each() foo; where foo can be any arbitrary expression that evaluates to a delegate, is probably never going to be allowed. > I wonder why it's not used more? It seems quite readable, maybe there is a performance impact (shouldn't happen if the compiler inline the each function call). > > Of course both ways are a little more verbose than Ruby due to the static typing, but they are still very good. Ok by me if its a little more verbose, as long as the verbosity is really the minimal required to make static typing work. > I wonder if with templates there couldn't be a way to have the "item" element declared implicitely with the correct type? I think we covered most of the bases in the "Prettier iterator implementations in D?" thread in digtalmars.D. Reiner suggested that some types could potentially be deduced and substituted with 'auto'. --bb |
October 25, 2006 Re: foreach, an analogy | ||||
---|---|---|---|---|
| ||||
Posted in reply to clayasaurus | clayasaurus wrote: > Here is my view on foreach_reverse > > 1) I really like the idea of foreach being the defacto-iterator for D Me too. > 2) foreach_reverse allows me to implement an opApply function to my doubly linked list template for not only forward iteration, but backwards iteration as well! Otherwise, I'd have to pass it a &list.reverse delegate which is hackish. In C#, the foreach construct operates over arrays or objects that implement the IEnumerable<T> interface (which includes the ICollection<T> subinterface). In Java, the "enhanced for loop" operates over arrays or objects that implement the Iterable<T> interface (which includes the Collection<T> sub-interface). As far as I'm concerned, each class should be responsible for determining which iterators it offers. A doubly-linked list could provide: DoublyLinkedList.getForwardIterator(); DoublyLinkedList.getReverseIterator(); Whereas a binary tree might provide even more: BinaryTree.getInOrderIterator(); BinaryTree.getReverseOrderIterator(); BinaryTree.getDepthFirstIterator(); BinaryTree.getBreadthFirstIterator(); Then, the foreach just iterates through any object that's iterable. Like this: IEnumerable<T> iterator = myBinaryTree.getDepthFirstIterator(); foreach(T item in iterator) { // do stuff with item } A single mechanism for all different kinds of iteration scenarios. The ECMA C# specification (starting on page 236) gives a thorough description of how compilers should implement foreach: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf I think it's a very elegant solution. In D, even overlooking the presence of a fifteen-letter keyword ("foreach_reverse"), the ugliest part is the presence of the opApplyReverse() method, which suggests that the collection object should be responsible for its own iteration, whereas I think iteration should be delegated to a separate object. --Benji Smith |
October 26, 2006 Re: foreach, an analogy | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benji Smith | Benji Smith wrote: > clayasaurus wrote: > >> Here is my view on foreach_reverse >> >> 1) I really like the idea of foreach being the defacto-iterator for D > > > Me too. > >> 2) foreach_reverse allows me to implement an opApply function to my doubly linked list template for not only forward iteration, but backwards iteration as well! Otherwise, I'd have to pass it a &list.reverse delegate which is hackish. > > > In C#, the foreach construct operates over arrays or objects that implement the IEnumerable<T> interface (which includes the ICollection<T> subinterface). > > In Java, the "enhanced for loop" operates over arrays or objects that implement the Iterable<T> interface (which includes the Collection<T> sub-interface). > > As far as I'm concerned, each class should be responsible for determining which iterators it offers. A doubly-linked list could provide: > > DoublyLinkedList.getForwardIterator(); > DoublyLinkedList.getReverseIterator(); > > Whereas a binary tree might provide even more: > > BinaryTree.getInOrderIterator(); > BinaryTree.getReverseOrderIterator(); > BinaryTree.getDepthFirstIterator(); > BinaryTree.getBreadthFirstIterator(); > > Then, the foreach just iterates through any object that's iterable. Like this: > > IEnumerable<T> iterator = myBinaryTree.getDepthFirstIterator(); > foreach(T item in iterator) { > // do stuff with item > } Or, using the current situation: # foreach (item; &myBinaryTree.depthFirstIterator) { # // do stuff with item # } I think that is about as expressive as could be needed? > A single mechanism for all different kinds of iteration scenarios. > > The ECMA C# specification (starting on page 236) gives a thorough description of how compilers should implement foreach: > > http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf > > I think it's a very elegant solution. > > In D, even overlooking the presence of a fifteen-letter keyword ("foreach_reverse"), the ugliest part is the presence of the opApplyReverse() method, which suggests that the collection object should be responsible for its own iteration, whereas I think iteration should be delegated to a separate object. > > --Benji Smith -- Chris Nicholson-Sauls |
January 26, 2007 Re: foreach, an analogy | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote:
> Bruno Medeiros wrote:
>> As of DMD now, the only advantage in 'foreach_reverse' is ephemerous: it allows efficient reverse iteration of arrays.
>
> That's the most important use case.
>
>> But couldn't the compiler easily detect this:
>> foreach(Foo f; &fooarray.opApplyReverse) { ...
>> and and compile it as if it were a:
>> foreach_reverse(Foo f; fooarray) { ...
>
> Yes, it could. But it looks like a hack. A little syntactic sugar makes a big difference.
What about:
foreach (Foo f; array.reverse) {}
The compiler would optimize.
-Joel
|
January 26, 2007 Re: foreach, an analogy | ||||
---|---|---|---|---|
| ||||
Posted in reply to janderson | janderson wrote:
> Walter Bright wrote:
>> Bruno Medeiros wrote:
>>> As of DMD now, the only advantage in 'foreach_reverse' is ephemerous: it allows efficient reverse iteration of arrays.
>>
>> That's the most important use case.
>>
>>> But couldn't the compiler easily detect this:
>>> foreach(Foo f; &fooarray.opApplyReverse) { ...
>>> and and compile it as if it were a:
>>> foreach_reverse(Foo f; fooarray) { ...
>>
>> Yes, it could. But it looks like a hack. A little syntactic sugar makes a big difference.
>
>
> What about:
>
> foreach (Foo f; array.reverse) {}
>
> The compiler would optimize.
>
> -Joel
Blast from the past!
In D, array.reverse calls the method 'reverse'.
Anyway, elsewhere in that thread I think Walter basically said, yes the compiler could probably be made to optimize such a thing, but it would be difficult. And he doesn't seem to see anything wrong with foreach_reverse, so I guess he's not inclined to try to make it work that way.
--bb
|
January 26, 2007 Re: foreach, an analogy | ||||
---|---|---|---|---|
| ||||
Posted in reply to janderson | janderson wrote:
> Walter Bright wrote:
>> Bruno Medeiros wrote:
>>> As of DMD now, the only advantage in 'foreach_reverse' is ephemerous: it allows efficient reverse iteration of arrays.
>>
>> That's the most important use case.
>>
>>> But couldn't the compiler easily detect this:
>>> foreach(Foo f; &fooarray.opApplyReverse) { ...
>>> and and compile it as if it were a:
>>> foreach_reverse(Foo f; fooarray) { ...
>>
>> Yes, it could. But it looks like a hack. A little syntactic sugar makes a big difference.
>
>
> What about:
>
> foreach (Foo f; array.reverse) {}
>
> The compiler would optimize.
But the array would still be reversed after the foreach.
L.
|
January 26, 2007 Re: foreach, an analogy | ||||
---|---|---|---|---|
| ||||
Posted in reply to Lionello Lunesu | Lionello Lunesu wrote:
> janderson wrote:
>> Walter Bright wrote:
>>> Bruno Medeiros wrote:
>>>> As of DMD now, the only advantage in 'foreach_reverse' is ephemerous: it allows efficient reverse iteration of arrays.
>>>
>>> That's the most important use case.
>>>
>>>> But couldn't the compiler easily detect this:
>>>> foreach(Foo f; &fooarray.opApplyReverse) { ...
>>>> and and compile it as if it were a:
>>>> foreach_reverse(Foo f; fooarray) { ...
>>>
>>> Yes, it could. But it looks like a hack. A little syntactic sugar makes a big difference.
>>
>>
>> What about:
>>
>> foreach (Foo f; array.reverse) {}
>>
>> The compiler would optimize.
>
> But the array would still be reversed after the foreach.
>
> L.
Is that what he was talking about? I forgot that 'reverse' was an actual existing method that mutates the array. If that's what you meant, then, yeh, what Lionello said.
--bb
|
Copyright © 1999-2021 by the D Language Foundation