View mode: basic / threaded / horizontal-split · Log in · Help
October 24, 2006
Re: foreach, an analogy
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
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
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
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
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
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
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
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
Next ›   Last »
2 3 4 5 6
Top | Discussion index | About this forum | D home