Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Hash assignment: Undocumented feature?

by fsavigny (Novice)
on Aug 11, 2013 at 13:54 UTC ( #1049007=perlquestion: print w/replies, xml ) Need Help??
fsavigny has asked for the wisdom of the Perl Monks concerning the following question:

No, I am all but sure I am NOT the person who has discovered an undocumented feature - but still, I have not found this explained in either Programming Perl or the perldata manpage:

Is it a reliable feature of Perl that if you assign to a key more than once in one list, then the latest overwrites any previous ones? I do not mean single assignments in $hash{foo} = 4 style, but when this occurs in a list:

%hash = ( foo => 3, bar => 2, foo => 1, foo => 10); print join " ", %hash, "\n"; # outputs: bar 2 foo 10

Any other experiments I've run have also made it seem as if the last assignment overwrites anything before it. Is this documented anywhere? It looks to me as if it could be interesting as a method of changing several values at once.

Best regards, Florian

Replies are listed 'Best First'.
Re: Hash assignment: Undocumented feature?
by vsespb (Chaplain) on Aug 11, 2013 at 14:00 UTC
    see perldata:
    If a key appears more than once in the initializer list of a hash, the last occurrence wins:

      Thanks very much! That should put me to shame, and it's right; on, there it is. My Gentoo, though constantly updated, seems to have an outdated version of perldata (v5.12.4, dated 2011-06-07), which does definitely not contain this information (there is also no %circle hash with different radii).

      But surely this must have been like that for longer than two years???

      (I hope I will be able to give a good example for why I think it's useful, but I'm having to dash off right now.)

        Perhaps you're new enough to the concept of a hash to not fully understand that any hash "bucket" acts the same as an array "bucket". In other words,
            $hash{'bucket'} = 'something';
        is similar in concept to

        If you then, say
            $array[5]='something else';
        hopefully you understand that $array[5] has been written over with the new information; just extend that concept to
            $hash{'bucket'} = 'something else';

        So, no this is not new behavior, but the way hashes, across all the languages that implement some sort of hash, are supposed to work.


        > But surely this must have been like that for longer than two years???

        Yes, but seems indeed documented only in perl 5.18.

        IMHO this feature used _very_ often. And works like that for ages. So don't worry.

Re: Hash assignment: Undocumented feature?
by AnomalousMonk (Chancellor) on Aug 11, 2013 at 16:17 UTC
    ... a method of changing several values at once.

    I don't see this as a valid way of looking at this behavior. A hash key is always unique, and a hash key always has exactly one scalar value, although this scalar may be a reference to... well, anything, opening up vast possibilities for data structures, code dispatch tables, etc., etc., etc. So the only way to "[change] several values at once" is to replace a (scalar) reference to a bunch of stuff with another (scalar) reference to a different bunch of stuff.

    Maybe one useful approximation to "changing several values at once", but with "changing" better understood as "dealing with", is the Perl idiom for implementing named, defaulted, non-positional function arguments. It goes something like:

    >perl -wMstrict -le "sub D { my %defaults = qw(foo 999 bar 888 baz 777); ;; my ($hr_args) = @_; my %arguments = (%defaults, %{ $hr_args || {} }); ;; print qq{foo $arguments{foo} bar $arguments{bar} baz $arguments{b +az}}; } ;; D(); ;; D({bar => 2}); ;; D({baz => 1, foo => 3}); " foo 999 bar 888 baz 777 foo 999 bar 2 baz 777 foo 3 bar 888 baz 1

      (Oops. Didn't really need to dash off, on second thought.) I slightly suspect your example is more complex than I can deal with. What I meant is simply something like this (and I think it does not matter if the values are simple scalars or references to something complex):

      %what_all_workers_have = ( holidays => 30, hours_per_week => 40, office_space => 10, job_title => "Clerk", ); ## turning to John, who is a wheelchair user: %what_john_has = ( %what_all_workers_have, office_space => 20, # needs room to maneuvre hours_per_week => 35, # needs more breaks );

      One needn't even worry if %workers_have actually contains the keys office_space and hours_per_week. It will either add or overwrite them, whichever is required. To me, this seems quite elegant and time-saving. In any case, it's less code to type than any other version I could think of.

        %what_john_has = ( %what_all_workers_have, office_space => 20, # needs room to maneuvre hours_per_week => 35, # needs more breaks );

        That's kinda like what
            my %arguments = (%$hr_defaults, %{ $hr_args || {} });
        is doing in my example code: as you've written,  %what_all_workers_have is the default of what a particular worker has.

Re: Hash assignment: Undocumented feature?
by sundialsvc4 (Abbot) on Aug 13, 2013 at 04:17 UTC

    I simply read the OP as denoting uncertainty as to exactly what will happen if the same key is specified more-than-once in a hash initialization statement such as the one shown.   The definitive and now-documented answer seems to be:   that the initialization will reliably proceed left-to-right ... so that the rightmost occurrence of any key, by virtue of being the last assignment that is made for that particular key as the statement is executed, will always “win.”   Perl will not, so far as I know, generate any errors or warnings ... it probably isn’t what you meant to do, but it’s not illegal.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1049007]
Approved by Perlbotics
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (5)
As of 2018-06-21 05:34 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (117 votes). Check out past polls.