I was bit yesterday by a bug/misfeature in foreach regarding iterators. After getting the index and/or value from the iterator, it increments it before executing the loop code. I.e. the following will throw an error:
String.Iterator iter = String.Iterator ("foo"); foreach (iter; int idx;) if (idx != iter->index()) error ("wtf?\n");
I consider it a bug and intend to change foreach so that the iterator is incremented after the loop instead.
Unfortunately that change can have nasty effects in code that expects foreach to behave like this. I can either change it in 7.5 only and fix some #pike 7.4 compatibility goo, or I can "ignore" the compat issue and fix it in both 7.4 and 7.5. I'm actually inclined to do the latter, under the assumption that there still is very little code that use iterators this way (Grubbas new compiler is the only example I know). If it stays as it is in 7.4 it can be cumbersome to update code to 7.5.
Not sure though if we can get away with pulling a stunt like that this long after the 7.4 release. Does anyone know of more code that depends on this foreach quirk?
I know my code doesn't care.
/ Peter Bortas
Previous text:
2003-09-04 13:43: Subject: foreach problem
I was bit yesterday by a bug/misfeature in foreach regarding iterators. After getting the index and/or value from the iterator, it increments it before executing the loop code. I.e. the following will throw an error:
String.Iterator iter = String.Iterator ("foo"); foreach (iter; int idx;) if (idx != iter->index()) error ("wtf?\n");
I consider it a bug and intend to change foreach so that the iterator is incremented after the loop instead.
Unfortunately that change can have nasty effects in code that expects foreach to behave like this. I can either change it in 7.5 only and fix some #pike 7.4 compatibility goo, or I can "ignore" the compat issue and fix it in both 7.4 and 7.5. I'm actually inclined to do the latter, under the assumption that there still is very little code that use iterators this way (Grubbas new compiler is the only example I know). If it stays as it is in 7.4 it can be cumbersome to update code to 7.5.
Not sure though if we can get away with pulling a stunt like that this long after the 7.4 release. Does anyone know of more code that depends on this foreach quirk?
/ Martin Stjernholm, Roxen IS
Speaking about iterators and quirks, there's one in the iterator interface too: The step operation uses `+=, which is fairly logical for the iterator implementor but not for users; the only way to explicitly step an iterator is like this:
iter->`+= (1);
Clumsy syntax, and it invites to make the mistake of using the operator += directly:
iter += 1;
That won't work since it normally copies the iterator instead of changing it destructively. (Remember that a += b is equivalent to a = a + b except that a is evaluated only once. Hence there's no relation between the operator += and the lfun `+=.)
We ought to fix this somehow. I can see two alternatives:
1. Add a global step_iterator function to accompany get_iterator. It'd be used like this
step_iterator (iter, 1);
and do an lfun call to `+= (which would work even if it's static).
Actually, the function could be used to make an lfun call to `+= in any object, so perhaps it should be called "destructive_add" or something like that, but that'd be just as unintuitive in the iterator context as iter->`+=(1).
2. Rename `+= to "step" in the iterator interface, so that one can do
iter->step (1);
instead.
The necessary compatibility goo to cope with iterators that only define `+= is complicated, though: A #pike 7.4 directive in the file where the iterator is defined should be enough. That means that the compiler has to automatically add an alias "step" for `+= in any class that seems to be an iterator. Messy.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-09-04 13:43: Subject: foreach problem
I was bit yesterday by a bug/misfeature in foreach regarding iterators. After getting the index and/or value from the iterator, it increments it before executing the loop code. I.e. the following will throw an error:
String.Iterator iter = String.Iterator ("foo"); foreach (iter; int idx;) if (idx != iter->index()) error ("wtf?\n");
I consider it a bug and intend to change foreach so that the iterator is incremented after the loop instead.
Unfortunately that change can have nasty effects in code that expects foreach to behave like this. I can either change it in 7.5 only and fix some #pike 7.4 compatibility goo, or I can "ignore" the compat issue and fix it in both 7.4 and 7.5. I'm actually inclined to do the latter, under the assumption that there still is very little code that use iterators this way (Grubbas new compiler is the only example I know). If it stays as it is in 7.4 it can be cumbersome to update code to 7.5.
Not sure though if we can get away with pulling a stunt like that this long after the 7.4 release. Does anyone know of more code that depends on this foreach quirk?
/ Martin Stjernholm, Roxen IS
I prefer variant 2. Regarding the compat problem, I think using `+=() as fallback if step() doesn't exist is a more viable solution.
/ Henrik Grubbström (Lysator)
Previous text:
2003-09-04 14:49: Subject: Iterator interface
Speaking about iterators and quirks, there's one in the iterator interface too: The step operation uses `+=, which is fairly logical for the iterator implementor but not for users; the only way to explicitly step an iterator is like this:
iter->`+= (1);
Clumsy syntax, and it invites to make the mistake of using the operator += directly:
iter += 1;
That won't work since it normally copies the iterator instead of changing it destructively. (Remember that a += b is equivalent to a = a + b except that a is evaluated only once. Hence there's no relation between the operator += and the lfun `+=.)
We ought to fix this somehow. I can see two alternatives:
Add a global step_iterator function to accompany get_iterator. It'd be used like this
step_iterator (iter, 1);
and do an lfun call to `+= (which would work even if it's static).
Actually, the function could be used to make an lfun call to `+= in any object, so perhaps it should be called "destructive_add" or something like that, but that'd be just as unintuitive in the iterator context as iter->`+=(1).
Rename `+= to "step" in the iterator interface, so that one can do
iter->step (1);
instead.
The necessary compatibility goo to cope with iterators that only define `+= is complicated, though: A #pike 7.4 directive in the file where the iterator is defined should be enough. That means that the compiler has to automatically add an alias "step" for `+= in any class that seems to be an iterator. Messy.
/ Martin Stjernholm, Roxen IS
That's a bit blunt and it can never be turned off, but yes it's much simpler.
There's also the case of keeping compatibility with pike code that use iterators explicitly through `+=. I.e. we'd either have to add an alias `+= for "step" in new iterators, or automatically rewrite
x->`+= (y);
to
if (x->`+=) x->`+= (y); else x->step (y);
in pike code that uses #pike 7.4. Bläää.. :(
What I'd really like to do is to scrap the "rewriting" of a += b to a = a + b. Many things would be much simpler if the operator += used the lfun `+= regardless of the number of references.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-09-04 14:53: Subject: Iterator interface
I prefer variant 2. Regarding the compat problem, I think using `+=() as fallback if step() doesn't exist is a more viable solution.
/ Henrik Grubbström (Lysator)
The cleanest is ofcourse to ignore the compat, since it's between minors.
/ Henrik Grubbström (Lysator)
Previous text:
2003-09-04 15:19: Subject: Iterator interface
That's a bit blunt and it can never be turned off, but yes it's much simpler.
There's also the case of keeping compatibility with pike code that use iterators explicitly through `+=. I.e. we'd either have to add an alias `+= for "step" in new iterators, or automatically rewrite
x->`+= (y);
to
if (x->`+=) x->`+= (y); else x->step (y);
in pike code that uses #pike 7.4. Bläää.. :(
What I'd really like to do is to scrap the "rewriting" of a += b to a = a + b. Many things would be much simpler if the operator += used the lfun `+= regardless of the number of references.
/ Martin Stjernholm, Roxen IS
Huh? That's why there _should_ be compat. If we were speaking of Pike 8 here then we could motivate disregarding it.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-09-04 15:24: Subject: Iterator interface
The cleanest is ofcourse to ignore the compat, since it's between minors.
/ Henrik Grubbström (Lysator)
What I'd really like to do is to scrap the "rewriting" of a += b to a = a + b. Many things would be much simpler if the operator += used the lfun `+= regardless of the number of references.
I'd say the usability aspect alone is reason enough to do that change.
/ Johan Sundström (utan sälskap)
Previous text:
2003-09-04 15:19: Subject: Iterator interface
That's a bit blunt and it can never be turned off, but yes it's much simpler.
There's also the case of keeping compatibility with pike code that use iterators explicitly through `+=. I.e. we'd either have to add an alias `+= for "step" in new iterators, or automatically rewrite
x->`+= (y);
to
if (x->`+=) x->`+= (y); else x->step (y);
in pike code that uses #pike 7.4. Bläää.. :(
What I'd really like to do is to scrap the "rewriting" of a += b to a = a + b. Many things would be much simpler if the operator += used the lfun `+= regardless of the number of references.
/ Martin Stjernholm, Roxen IS
That change would render problems with Gmp.
/ Henrik Grubbström (Lysator)
Previous text:
2003-09-04 15:25: Subject: Iterator interface
What I'd really like to do is to scrap the "rewriting" of a += b to a = a + b. Many things would be much simpler if the operator += used the lfun `+= regardless of the number of references.
I'd say the usability aspect alone is reason enough to do that change.
/ Johan Sundström (utan sälskap)
Not if `+= was removed from the Gmp interface, or if we added another lfun `destructive+ or similar it could use instead.
No, the problem is that there are places here and there where things like
m += (["foo": 17]);
are done with the explicit intention that the original mapping in m stays unchanged. They aren't easy to find.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-09-04 15:27: Subject: Iterator interface
That change would render problems with Gmp.
/ Henrik Grubbström (Lysator)
Not if `+= was removed from the Gmp interface, or if we added another lfun `destructive+ or similar it could use instead.
Hmm, no. That would require that a += b still falls back to a = a + b if there's no `+= in a, which wouldn't be good at all.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-09-04 15:32: Subject: Iterator interface
Not if `+= was removed from the Gmp interface, or if we added another lfun `destructive+ or similar it could use instead.
No, the problem is that there are places here and there where things like
m += (["foo": 17]);
are done with the explicit intention that the original mapping in m stays unchanged. They aren't easy to find.
/ Martin Stjernholm, Roxen IS
Not if a+=b; is compiled to a=a->`+=(b); Ie. give the class the option of still creating a copy if it wishes. (The norm would be to return this_object() from `+= of course.) Also, this is how `+= works now.
/ Fredrik (Naranek) Hubinette (Real Build Master)
Previous text:
2003-09-04 15:27: Subject: Iterator interface
That change would render problems with Gmp.
/ Henrik Grubbström (Lysator)
Ie. give the class the option of still creating a copy if it wishes.
I don't think that'd be a good idea since it'd get difficult to know if the operator += is destructive (with side-effects) or not. In that case it's better to leave it as it is, i.e. consider it to be nothing but an optimization and not make it part of interfaces.
Still, there's clearly a need for an lfun-like interface to make explicit destructive calls. It probably can't be operator-like though, since I don't think we can figure out a whole new set of destructive operators that fits well enough. Not that I wouldn't give it a try.
Also, this is how `+= works now.
Actually not right now in 7.5. The assignment is optimized away there. Could be considered a bug, but otoh there's never any need to define a `+= at all if it can't be destructive.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-09-05 03:19: Subject: Iterator interface
Not if a+=b; is compiled to a=a->`+=(b); Ie. give the class the option of still creating a copy if it wishes. (The norm would be to return this_object() from `+= of course.) Also, this is how `+= works now.
/ Fredrik (Naranek) Hubinette (Real Build Master)
pike-devel@lists.lysator.liu.se