Anthony Veckey
Anthony Veckey

Reputation: 101

What is the '@(' doing in this Perl code?

In this code snippet:

    use strict;
    use warnings;
    use Data::Dumper;
    my $r = [qw(testing this thing)];

    print Dumper($r);
    foreach my $row (@({$r})
    {
        print "$row\n";
        $row .= 'mod';
    }
    print Dumper($r);
    print Dumper(@({$r});

I figured out that the '(' after the '@' in the foreach is causing this not to loop correctly. I have no idea why this code even works as there is no ending parenthesis. What is this doing? It looks to be creating a new variable on the fly, but shouldn't 'use strict' have fired or something?

Please help explain what that '@(' is doing and why it still runs without an ending parenthesis.

Upvotes: 9

Views: 327

Answers (4)

gangrene
gangrene

Reputation: 21

It didn't click for me, that this is a hash slice, until I ran it through B::Concise

$ perl -MO=Concise junk 
    Scalar value @({$r} better written as $({$r} at junk line 7.
    Scalar value @({$r} better written as $({$r} at junk line 13.
    junk syntax OK
    1l <@> leave[1 ref] vKP/REFC ->(end)
    1     <0> enter ->2
    ...
    ...
    1h             <@> hslice lKM ->1i
    1d                <0> pushmark s ->1e
    1e                <0> padsv[$r:335,339] l ->1f
    1g                <1> rv2hv[t17] sKR/3 ->1h
    1f                   <#> gv[*(] s ->1g
    -              <1> ex-rv2cv sK/2 ->-
    1i                <#> gv[*Dumper] s ->1j

hslice means hash slice :) get to know your B:: tree, its really helpfull

Upvotes: 0

Eric Strom
Eric Strom

Reputation: 40142

That is a hash slice of the %( variable, which being part of the *( glob, is exempt from strict vars. This is true for variables that Perl has predefined, in this case $( and also for all of the other glob slots for the names of punctuation variables. All punctuation variables are global across all packages, and their fully qualified names are the short forms: $), @), %), &)... Since strict 'vars' does not apply to fully qualified names, none of these names are errors.

Expanding a bit:

@({$r};
@{(}{$r};
@{'main::('}{$r};  # needs strict refs to be off

Those lines are all equivalent.

With use warnings; perl will let you know that it would be better to write a slice of a single value with a $ sigil:

$({$r};
${(}{$r};
${'main::('}{$r};  # needs strict refs to be off

Which in trying to resolve a typo would have pointed you in the right spot. Which is why you should always use both warnings and strictures.

For more detail, the perlvar manpage shows all of the punctuation variables with at least one sigil or another. And if you wanted a reference about the scoping of punctuation variables, the package docs have that.


All the punctuation variables are also immune to used only once warnings, and that might be a bug...

Upvotes: 8

Keith Thompson
Keith Thompson

Reputation: 263217

When I run perl -cw on it, it says:

Scalar value @({$r} better written as $({$r} at tmp.pl line 7.
Scalar value @({$r} better written as $({$r} at tmp.pl line 13.

$r is a reference to an array. As Eric Strom just posted, @({$r} is a hash slice of the %( hash variable.

You never declared %(, and it's not one of the predefined variables listed in perldoc perlvar. So why doesn't use strict; use warnings; cause Perl to complain about it? It probably just assumes that any variable whose name is a punctuation character is predefined (simpler than keeping track of which ones really are, some of which might be undef anyway).

Note that $( is a valid predefined variable (it's the real group-id of the current process), so something that looks like a mismatched parenthesis isn't necessarily an error.

It looks like it's simply a typo that, for obscure reasons, Perl didn't complain about.

Change @({$r} to @{$r} to do what you (presumably) actually meant to do.

Upvotes: 2

ikegami
ikegami

Reputation: 385590

@({$r} is a hash slice (documented in perldata) of the hash %(.

%h = (a=>1, b=>2, c=>3);
say for @h{qw( a c )};  # 1 3

Perl itself doesn't use %(, so it was surely empty.

You surely meant to use @{$r}, a rather complex way or writing @$r.

Upvotes: 3

Related Questions