Re: Why Doesn't each() DWIM?
by Anonymous Monk on May 27, 2004 at 21:06 UTC
|
From each docs:
When the hash is entirely read, a null array is returned in list context (which when assigned produces a false (0) value), and undef in scalar context. The next call to each after that will start iterating again. There is a single iterator for each hash, shared by all each, keys, and values function calls in the program; it can be reset by reading all the elements from the hash, or by evaluating keys HASH or values HASH.
Perhaps you don't like it, but it's documented.
If you want each to restart, you need to finish reading.
Put a my $x = keys %hash; between the two loops, and it will work as you expect.
| [reply] [d/l] |
|
If you have 5.8.3 or later, it's more efficient to use keys %hash; in a void context rather than a scalar context if you only want to reset the iterator.
This avoids the need to calculate the number of keys in the hash, which for large and/or tied hashes can potentially be an expensive operation.
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
| [reply] [d/l] |
|
I think the question is more along the lines of "why does it work this way" as opposed to "does it work this way" or "is this behavior documented". Can you think of a good scenario where not resetting each is a desired behavior?
| [reply] |
|
Yea.
I am just wondering if there is a reason Perl won't do it for me? Why isn't there a little Do What I Mean in there.
Is there a technical reason why that piece of DWIMmery would be considered harmful at some edge case?
| [reply] |
|
Perl already does what I mean in this case. If it did what you wanted, my expectations would be violated. Also, let's say that at the end of a loop the iterator on each() was reset, how would you get the behavior where it wasn't reset when you need it?
| [reply] |
|
|
Is there a technical reason why that piece of DWIMmery would be considered harmful at some edge case?
I can think of one. Whether it is right or not is another matter :)
There would be times when you wanted to return to your position in the hash.
If the iterator (or hashkey pointer) was reset everytime the program left a control loop, you would have to save it in a variable and then restore it each time you went into another control structure.
I don't see this as being a bad thing - other languages do it like this. I also don't know why it wasn't done this way rather than the way it currently is.
Having said that, I have found this to be a problem before, but some careful data structure design worked around it just fine.
____________________
Jeremy
I didn't believe in evil until I dated it.
| [reply] |
Re: Why Doesn't each() DWIM?
by chromatic (Archbishop) on May 27, 2004 at 22:25 UTC
|
why doesn't each automatically reset after loops are exited?
How does it know when you've exited a loop?
That's not a flippant question. Consider more complicated control flows. For example, with an iterator interface that abstracts away the hash to where you can't reset it, how is perl to tell when you want to reset the hash iterator?
I suspect that there's no meaningful algorithm to figure this out in a language that allows you to define your own flow of control.
| [reply] |
Re: Why Doesn't each() DWIM?
by Abigail-II (Bishop) on May 27, 2004 at 22:58 UTC
|
Well, in such a case, you would have to DWIM while, not each. each has no concept of blocks or loops.
Abigail | [reply] |
Re: Why Doesn't each() DWIM?
by hardburn (Abbot) on May 27, 2004 at 20:54 UTC
|
It is explicilty documented that hashes never, never, never have any meaningful order to them. So your "what you would expect" output is never going to be guarenteed to happen.
Now, for having each be localized . . . maybe. It might cause problems with tied hashes. I'll leave it to someone more familer with the internals.
----
send money to your kernel via the boot loader.. This and more wisdom available from Markov Hardburn.
| [reply] [d/l] |
|
hashes never, never, never have any meaningful order to them.
Right, right. I am not asking that a hash have order; rather, I just want each call to each to iterate over the entire hash; rather than having to make an explicit reset call (my $x = keys %hash) between calls to each.
| [reply] [d/l] |
Re: Why Doesn't each() DWIM?
by thospel (Hermit) on May 29, 2004 at 12:25 UTC
|
But actually, you probably don't care what the each state at
the end of your loop is. You care about the state at the beginning, so you will know
that you potentially process all elements. And these two
are only the same if you only use each inside loops.
However, it's perfectly ok to have code like:
# Suppose I know the hash has at least two entries, and
# it's freshly restarted
# Process first entry
my($tag, $val) = each %hash) ;
do_something($tag, $val);
#Process second entry
($tag, $val) = each %hash;
do_something($tag, $val);
more_processing();
No loop here, so I don't suppose you would want to change
the each semantics here.
But now suppose more_processing calls your while loop
using each, which can also be called from other points in
the program. You will still have the problem of not knowing
the state, even with your proposed modification to the
semantics of loops/each. So you'd have to reset the hash
anyways.
So in short, I don't think your proposal would make the
use of each easier, while the current sometimes useful behaviour would be lost. So all in all your proposal would be a loss. | [reply] [d/l] |
Re: Why Doesn't each() DWIM?
by ambrus (Abbot) on May 28, 2004 at 17:30 UTC
|
| [reply] [d/l] |