http://qs321.pair.com?node_id=11137614

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

So, this is a curious construct, which I'd be interested in hearing some deep esoteric explanation for (basically, explain the assignment of the hash: @b{@f}=(); ). How does the hash get assigned by using the list symbol on it?

$> perl -M'Data::Dumper' -le '@f=("f1","f2","f3"); my %b; @b{@f}=();pr +int Dumper(\@f); print Dumper(\%b)' $VAR1 = [ 'f1', 'f2', 'f3' ]; $VAR1 = { 'f1' => undef, 'f3' => undef, 'f2' => undef };

Replies are listed 'Best First'.
Re: Hash Curious
by choroba (Cardinal) on Oct 15, 2021 at 23:34 UTC
    See Slices.

    Also, it's faster than assigning the keys one by one, as the loop runs in C rather than Perl.

    #!/usr/bin/perl use warnings; use strict; my @keys = 'a' .. 'z'; sub one_by_one { my %hash; undef $hash{$_} for @keys; } sub slice { my %hash; @hash{@keys} = (); } use Benchmark qw{ cmpthese }; cmpthese(-3, { one_by_one => \&one_by_one, slice => \&slice, }); __END__ Rate one_by_one slice one_by_one 267946/s -- -25% slice 359541/s 34% --

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Hash Curious
by LanX (Saint) on Oct 16, 2021 at 00:09 UTC
    choroba already pointed you to perldata#Slices ...

    But:

    > How does the hash get assigned by using the list symbol on it? ...

    > ... @b{@f}=();

    It's the same logic with $b{@f} = "value" where the LHS is a $scalar.

    It's the curlies {...} which qualify b as hash.

    Now with the @array sigil it becomes a list @b{@f}=();

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

      As an aside, I've always found Perl's treatment of sigils confusing - especially when using hash slices! So I applaud Raku's more uniform approach, amusingly explained by Damian Conway in this youtube talk (9:45-10:40) in the following two tables of which sigil to use when:

      PerlScalarArrayHash
      Full contents$@%
      Individual element$$$
      Multiple elements@$@@
      Multiple elements with keys%$%%

      RakuScalarArrayHash
      Full contents$@%
      Individual element$@%
      Multiple elements$@%
      Multiple elements with keys$@%

      I especially enjoyed TheDamian's quip at the 10:30 mark:

      It really does make everyone's lives easier ... except for people who are coding in both Perl 5 and Perl 6 at the same time. Your lives will be misery. :)

        I think the table is not fully accurate in the Hash column.

        • "Full contents" of %Hash returns a list of pairs
        • "Multiple elements" of @Hash{SLICE} returns a list of values

        NB: there is a new feature %Hash{SLICE} to return "Multiple pairs"

        DB<49> @H{a..d}=1..4 DB<50> x %H{d,b} 0 'd' 1 4 2 'b' 3 2 DB<51> x @H{d,b} 0 4 1 2 DB<52>

        edit
        One could argue that for reasons of symmetry there should be @Hash for a "Full list of values". But this collides with arrays, hence we have the operators values and keys

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

          The big dilemma with Perl5 was that it kept full backwards compatibility with Perl4.

          The big dilemma with Perl6 was that it kept no backwards compatibility with Perl5.

        ... sigh ...

        The ultimate reason for that sigil table for P5 is context propagation

        Take §{EXPR} = EXPR2 with § as first sigil

        • a $ will evaluate EXPR2 in scalar context
        • a @ or % will evaluate EXPR2 in list context
        I'm always confused how Perl6 is handling that, and I can't remember it long after looking it up.

        BUT this is one of the biggest obstacle for backwards compatibility.

        The table is also "cheating" in the scalar column, because %$ and @$ denotes de-referencing .

        Which is indeed a PITA in Perl5 and IMHO one of the top problems for beginners.

        E.g. in order to pass an array to a sub we have to reference

        func(\@arr);

        but inside the sub we need to start fiddling with array-refs and a new syntax with plenty of arrows

        sub func { my $arr =shift; print "First: $arr->[0]"; print "Nested List @{$arr->[0]}"; }

        I would rather have preferred a new lexical pragma in Perl5 to automatically alias "$ref-form" with "@list-form of a variable.

        I.e. the declaration my @arr automatically implies $arr =\@arr and (somehow) vice versa.

        Like this $arr[0] and $arr->[0] would lead to the same result and many arrows could be saved.

        This would come with the cost of fusing the namespace for scalars and arrays, but

        1. using the same symbol arr for different vars is considered bad style anyway
        2. it'll stay fully compatible to old code, by simply avoiding the pragma

        Perl inherited this dilemma from Perl4 where the list form of @arr was very convenient, but most other dynamic languages I know operate with the ref form (without sigil) by default.

        arr=[] is a ref/obj in JS, Python and Ruby

        If these languages need the flattened list form of arr they apply a method or a postfix syntax. You could say everything is a scalar there.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

        I don't quite agree with this table. Please consider the following code.
        constant term:<$container> = 1,2,3; say $container, $container.WHAT; # (1 2 3)(List) say "answer: $container"; # answer: 1 2 3 dd $container; # (1, 2, 3) # note the lack of naming of the container sub s($first, *@rest){ dd $first, @rest; } s($container); # $(1, 2, 3) # Array element = []
        Here, $container is not a container. It is a List of Values and also a scalar. In quote interpolation it is handled like a list but in a signature as a scalar. In plain Raku (not in a signature, not in a quote, regex, etc.) '$' may not indicate Scalar.