View mode: basic / threaded / horizontal-split · Log in · Help
October 18, 2006
Re: DMD 0.170 release
Oskar Linde wrote:
> Walter Bright wrote:
> 
>> Bill Baxter wrote:
>>
>>> I don't see how it helps.  If you can already do:
>>>    foreach(T item; &collection.reversed()) { }
>>
>>
>> That doesn't work for arrays.
> 
> 
> In what way does it not work? I have been doing:
> 
> foreach(x; "abcd".reverseView())
>     writef("%s",x);
> 
> prints "dcba"
> 
> For any type of built in array for a very long time (long before 0.170), 
> and it certainly seems to work for me.

How do you do that?  I just get
: undefined identifier reverseView
: function expected before (), not reverseView of type int
: cannot infer type for x
October 18, 2006
Re: DMD 0.170 release
Walter Bright wrote:
> Bill Baxter wrote:
>> I don't see how it helps.  If you can already do:
>>    foreach(T item; &collection.reversed()) { }
> 
> That doesn't work for arrays.

Is "foreach_reverse" just there for arrays? To me it dosen't bother to 
have a new keyword, but if it just exists to do:

for(int i = array.length - ; i >= 0; i--) {
	// ...
}

then it is realy superflous.

"foreach_reversed" just is useful for two things: arrays and lists. For 
arrays you can always type the code above. For lists, give them a 
"reversed" method that accepts a delegate, as I wrote. For other types 
the "foreach" dosen't guarantee the order! (map, tree, set, etc.)

So "for(;;)" appears 5% of the time, convert it to "forever". :-)

I repeat: is "foreach_reverse" just there for arrays?
October 18, 2006
Re: DMD 0.170 release
Ary Manzana wrote:
> Walter Bright wrote:
> 
>> Bill Baxter wrote:
>>
>>> I don't see how it helps.  If you can already do:
>>>    foreach(T item; &collection.reversed()) { }
>>
>>
>> That doesn't work for arrays.
> 
> 
> Is "foreach_reverse" just there for arrays? To me it dosen't bother to 
> have a new keyword, but if it just exists to do:
> 
> for(int i = array.length - ; i >= 0; i--) {
>     // ...
> }
> 
> then it is realy superflous.
> 
> "foreach_reversed" just is useful for two things: arrays and lists. For 
> arrays you can always type the code above. For lists, give them a 
> "reversed" method that accepts a delegate, as I wrote. For other types 
> the "foreach" dosen't guarantee the order! (map, tree, set, etc.)
> 
> So "for(;;)" appears 5% of the time, convert it to "forever". :-)
> 
> I repeat: is "foreach_reverse" just there for arrays?


No, it at least works for arrays and any class with an "opApplyReverse" 
method, and for any delegate you feel like passing in.

Thus you can even do something nonsensical like:

   foreach_reverse(int i; &aggregate.opApply()) { }

And use foreach_reverse to iterate forwards over aggregate.  The only 
thing foreach_reverse gets you is the ability to magically call the 
magic method "opApplyReverse" on an object that has it.  Otherwise 
foreach_reverse is pretty much identical to foreach.  Oh, and I guess 
you get the ability to iterate backwards over the built-in types, too, 
which don't actually have opApply/opApplyReverse methods, but I think 
their lack of those methods is a missed opportunity.  If they just had 
opApply (or acted like they did) then there wouldn't be any need to make 
special case rules for them in the language.

So basically, without foreach_reverse you can set it up so you can do 
reverse iteration with something like:
    foreach(int i; &aggregate.reversed())
or
    foreach(int i; reversed(aggregate))

With it, you get to say
    foreach_reverse(int i; aggregate)
which actually is equivalent to
    foreach_reverse(int i; &aggregate.opApplyReverse())
which is also equivalent to
    foreach(int i; &aggregate.opApplyReverse())

Basically foreach_reverse is 99% identical to foreach, but whereas 
foreach has a secret pact with all classes to call their opApply method, 
foreach_reverse has a secret pact to call opApplyReverse.  In all other 
respects they are identical.  Really either one can be made to iterate 
any direction and any way you wish.  foreach can iterate backwards if 
you want, and foreach_reverse can iterate forwards.

It is pretty much the antithesis of orthogonality to have multiple, very 
similar constructs offeing very nearly identical functionality.  And 
meanwhile poor old 'static' is made to do the jobs of twenty big men 
because we can't afford another keyword to lighten his workload.  Yet 
foreach_reverse gets a seat at the big boys' table just for knowing how 
to call opApplyReverse()?

Doesn't seem reasonable to me.

But it could be worse.  At least foreach_reverse doesn't steal your 
socks or eat babies.  He is pretty easy to ignore if you don't like him.

--bb
October 18, 2006
Re: DMD 0.170 release
Bill Baxter wrote:
> Oskar Linde wrote:
>> Walter Bright wrote:
>>
>>> Bill Baxter wrote:
>>>
>>>> I don't see how it helps.  If you can already do:
>>>>    foreach(T item; &collection.reversed()) { }
>>>
>>>
>>> That doesn't work for arrays.
>>
>>
>> In what way does it not work? I have been doing:
>>
>> foreach(x; "abcd".reverseView())
>>     writef("%s",x);
>>
>> prints "dcba"
>>
>> For any type of built in array for a very long time (long before 
>> 0.170), and it certainly seems to work for me.
> 
> How do you do that?  I just get
> : undefined identifier reverseView
> : function expected before (), not reverseView of type int
> : cannot infer type for x

Sorry. I wasn't very clear on this in my post. Here is a simple 
implementation that runs:

struct ReverseIterator(T:T[]) {
    T[] array;

    int opApply(int delegate(inout T) dg) {
        for (int i = array.length-1; i >= 0; i--) {
            if (auto status = dg(array[i]))
                return status;
        }
        return 0;
    }
}

ReverseIterator!(Array) reverseView(Array)(Array array) {
    ReverseIterator!(Array) iter; // = {array} => ICE
    iter.array = array;
    return iter;
}

import std.stdio;
void main() {
    foreach(x; "abcd".reverseView())
        writef("%s",x);
}
October 18, 2006
Re: DMD 0.170 release
Walter Bright wrote:
> Stewart Gordon wrote:
> 
>> Vladimir Kulev wrote:
>>
>>> J Duncan wrote:
>>>
>>>> Disagree with you, its a nice thing to have.
>>>
>>>
>>> There are many things which are nice to have, but only really 
>>> essential ones
>>> should be in language itself. Reverse foreach can be implemented in 
>>> other
>>> way.
>>
>>
>> So can ordinary foreach.
> 
> 
> All you really need is if and goto!


no, all you really need is goto and label variables

int i = 10;
loop:
	i--;
	goto [loop, quit][cast(int)(i==0)];
quit:
October 18, 2006
Re: DMD 0.170 release
Frits van Bommel wrote:
> Walter Bright wrote:
> 
>> Hasan Aljudy wrote:
>>
>>> Also, since foreach already takes two arguments (int i, T t) that is, 
>>> index and element, you can add a third argument, of bool type, with 
>>> the meaning "start in reverse mode"
>>> foreach( true, i, d; "Hello" )
>>> {
>>>     writefln( d );
>>> }
>>>
>>> should print:
>>> o
>>> l
>>> l
>>> e
>>> H
>>
>>
>> That would work, and something like it has been suggested before, but 
>> it is too obscure looking. When someone sees "foreach_reverse", I 
>> think it'll be very clear what's going on.
> 
> 
> There's no need to use booleans (at least, not directly):
> 
> enum Ordering : bool { forward, backwards, reversed = backwards }
> 
> That should produce much more readable code, but work the same. Can be 
> done right now, except you can't overload opApply for arrays :(. (Tell 
> me if I'm wrong, but I tried and it didn't work)


IIRC something like this should work

<code>
int go(char[], int delegate(inout char [, ...]) dg)
{
}

void main()
{
	foreach(char c; &("hello world".go)){}
}
</code>


if not, this should work:


<code>
template reverse(T)
{
	int delegate(int delegate(inout T)) reverse(T[] stuff)
	{
		auto ret = new struct
		{
			T[] data;
			int go(int delegate(inout T) dg)
			{
				for (int i = data.length-1; i >= 0; i--)
				{
					if(int result = dg(data[i]);
						return result;
				}
				return 0;
			}
		}
		ret.data = stuff;
		return &ret.go;
	}
}


...

	foreach(char c; reverse("hello world"));
	{
		...
	}
</code>
// I havent tried either so I expect there to be a few errors in them.
October 18, 2006
Re: DMD 0.170 release
Oskar Linde wrote:
> One example of a generalizing addition is Tomasz' suggestion for 
> trailing delegates. It generalizes foreach, foreach_reverse and even the 
> while-loop. Such an addition would not only make libraries simpler and 
> more powerful.

foreach_reverse is about as simple as one can get, from a user 
standpoint. It also works efficiently with arrays, which is hugely 
important because most of the time it will be used for arrays.

> It could also simplify the core language.

foreach_reverse was pretty trivial to implement. All the machinery was 
already there.

> What is design if not the pursuit of simplicity?

Simplicity is sometimes an elusive goal. For example, D started out with 
a simple syntax for function literals. Nobody used it, nobody even 
noticed it, people kept asking for the feature even after I pointed it 
out to them that D had it. Then, I figured out a way to eliminate some 
of the extra syntax for it, and voila! suddenly it gets noticed. This is 
even though the newer style is harder to parse and implement.

I also remember a thread here about D versus Ruby, and how everything 
was so simple in Ruby. It didn't matter that I showed how it could be 
done in D, it appeared to be simpler in Ruby, and that apparently made 
all the difference.
October 18, 2006
Re: DMD 0.170 release
Oskar Linde wrote:
> Walter Bright wrote:
>> Bill Baxter wrote:
>>> I don't see how it helps.  If you can already do:
>>>    foreach(T item; &collection.reversed()) { }
>>
>> That doesn't work for arrays.
> 
> In what way does it not work? I have been doing:
> 
> foreach(x; "abcd".reverseView())
>     writef("%s",x);
> 
> prints "dcba"

Try that, along with foreach_reverse, and look at the generated code.
October 18, 2006
Re: DMD 0.170 release
"BCS" <BCS@pathlink.com> wrote in message 
news:eh5kki$11t$4@digitaldaemon.com...

> no, all you really need is goto and label variables
>
> int i = 10;
> loop:
> i--;
> goto [loop, quit][cast(int)(i==0)];
> quit:

Who needs flow control?  If you need n iterations, copy and paste n times!
October 18, 2006
Re: DMD 0.170 release
Walter Bright wrote:
> Oskar Linde wrote:
>> One example of a generalizing addition is Tomasz' suggestion for 
>> trailing delegates. It generalizes foreach, foreach_reverse and even 
>> the while-loop. Such an addition would not only make libraries simpler 
>> and more powerful.
> 
> foreach_reverse is about as simple as one can get, from a user 
> standpoint. It also works efficiently with arrays, which is hugely 
> important because most of the time it will be used for arrays.

For what it's worth, I think iterative operation requirements all fall 
into one of three categories: forward, reverse, and unordered.  Forward 
iteration is by far the most common, so if semantic differences are 
involved, it should obviously be the prettiest ;-)  Reverse iteration is 
not terribly common, but it does find occasional use in search-oriented 
algorithms.  Unordered (for lack of a better term) can be used to 
describe any operation which has no ordering requirement and simply must 
be applied to all elements in a sequence.

I believe it is important that the compiler be able to recognize forward 
and reverse iteration at compile-time so optimizations may be applied. 
After all, that's the entire point of a built-in foreach in the first 
place.  Also, the compiler should be allowed to degenerate both forward 
and reverse iteration to the third category, unordered, when it can 
determine that visitation order has no impact on the operations being 
performed.  Some criteria for this may be if the statement block does 
not contain break, continue, or goto statements, and if all operations 
on sequence data are commutative.  Optionally, in instances where a 
statement block may not qualify for auto-degeneration, the user should 
be able to specify that it should be used anyway.  This would also allow 
user-defined types to implement unordered operations in non-trivial 
situations.  So we have something like this:

foreach() // the default: forward iteration, compiler may degenerate
foreach!(fwd)() // forward iteration, compiler may degenerate
foreach!(rev)() // reverse iteration, compiler may degenerate
foreach!(any)() // unordered: SSE ops may be used, concurrency, etc
foreach!(fwd,strict)() // forward iteration, compiler may not degenerate
foreach!(rev,strict)() // reverse iteration, compiler may not degenerate
foreach!(any,strict)() // unordered, same as without strict

(the above code above isn't intended to suggest syntax so much as to 
describe the operations and restrictions I think may eventually be useful)

Does this sound reasonable?  And can anyone suggest a cleaner syntax?


Sean
6 7 8 9 10 11 12 13 14
Top | Discussion index | About this forum | D home