davido has asked for the wisdom of the Perl Monks concerning the following question:

From the POD for Perl 5.14 I noticed the following in the documentation of each:

Starting with Perl 5.14, each can take a scalar EXPR, which must hold reference to an unblessed hash or array. The argument will be dereferenced automatically. This aspect of each is considered highly experimental. The exact behaviour may change in a future version of Perl.

while (($key,$value) = each $hashref) { ... }

My first reaction to reading that was why would we want to make a change that makes it harder to spot an error? Previously, each $hashref, or each \%hash, or even each { 'this' => 1 } would have been errors, and perl would tell you that. Now, they're legitimate, and Perl accepts them. But seeing such constructs in code could imply that the programmer has lost track of data-structure depth (though it might also be argued that we shouldn't care). When I type each %{ $hashref };, I know where I am in a datastructure. If we relax the requirements, we give up some of the visual syntactic cues.

It could be argued that the new relaxed syntax improves the ability to traverse datastructures without worrying about where we are in the structure of arbitrary depth.

I'm sure that a great deal of discussion goes into this sort of change, and I was just wondering if anyone can provide more insight as to the advantages of the newly relaxed syntax for each.


Dave

Replies are listed 'Best First'.
Re: New behavior of 'each' with respect to references
by ikegami (Patriarch) on May 17, 2011 at 17:58 UTC

    What really bugs me is that the behaviour of each(SCALAR) and friends is dependent on the internal storage format of the value passed to it.

    An object that overloads %{} is not considered a hash for each(SCALAR), so each(SCALAR) isn't safe to use unless you create the hash yourself.

    After years of work, they finally removed just about every trace of the "Unicode Bug" from the core only to add another bug of the same class. And they knew they were doing this!

Re: New behavior of 'each' with respect to references
by BrowserUk (Patriarch) on May 17, 2011 at 18:25 UTC

    My guess is that this is intended to facilitate recursive traversal of nested data-structures.

    As each can operate on arrays (and array refs) as well as hashes, it potentially allows the same loop to traverse both types of structure without having to differentiate between hashrefs and arrayrefs.

    That said, you still have to check you have a ref; that it is a ref to one of the two types and not a scalar etc. It doesn't immediately shout of any great reduction in code complexity.

    Add in the fact that it must be an unblessed ref which presumably excludes tied hashes and objects exporting hash or array like interfaces--which seems unnecessarially arbitrary--and it is quite hard to see any great benefit from the change.

    May be it is there, but it doesn't leap off the page at you.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: New behavior of 'each' with respect to references
by wind (Priest) on May 17, 2011 at 18:00 UTC

    It's not just each, but keys and values as well.

    If it were just hash references that were accepted, I'd say that it's not that big if a change. You're still getting some validation since it's only unblessed references that are accepted.

    However, what's going to be the expected results when performed on an array reference? Don't have a 5.14 installed to test it.

      keys(@a) returns the keys of the array elements: 0..$#a
      values(@a) returns the values of the array elements: @a

      Same for unblessed array references.

        Which just adds to the badness, since it's apparently not consistent with exists. This is 5.10:
        % perl -le '@a=0..4; delete $a[1]; print exists($a[1])||0' 0
        So the key "1" is present, but $a[1] doesn't exist...

        If just the auto-dereference of hashes had been added (and it had worked with tied scalars overloading %{}, and it didn't give some BS can't-turn-it-off error about "breaking encapsulation" like "smart" match does for blessed hashrefs (I don't have 5.14 ATM, so I'm not sure on this part)), it would probably be fine, but auto-dereference combined with broken acceptance of arrays just seems like a disaster.

Re: New behavior of 'each' with respect to references
by JavaFan (Canon) on May 17, 2011 at 21:06 UTC
    Previously, each $hashref, or each \%hash, or even each { 'this' => 1 } would have been errors, and perl would tell you that.
    Errors? I'd say that Perl is now doing the right thing with each $hashref. Perl now DWIM is the same as my @a; $a[1] = 0; being legal. Or autovivifying and autodereferencing filehandles. Sure, someone, somewhere is bound to have made a mistake when he wrote open $fh, "<", "foo", but surely, the convenience of DWIM for all the others surely outweights that.

    There isn't much in 5.14 that really excites me, but if I had to name one 5.14 I'd be using, it's the autodereferencing of arguments to keys, values and each.

Re: New behavior of 'each' with respect to references
by roubi (Hermit) on May 18, 2011 at 00:58 UTC
    I believe these posts are related to the changes: 1, 2, 3
    May provide the insight you're looking for.
Re: New behavior of 'each' with respect to references
by anonymized user 468275 (Curate) on May 18, 2011 at 15:39 UTC
    It doesn't seem that revolutionary to me. All of these functions take a hash argument, so imagining a simple implementation, they only have to test for a single argument as opposed to an even argument count and that it's a hash reference before going ahead with execution for the new feature.

    One world, one people