http://www.perlmonks.org?node_id=1220092

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

How does this create a loop? I was experimenting.
use 5.010; my @x = ("x" => 1); my $y = \@x; say $#@x[1];

Replies are listed 'Best First'.
Re: Code Loop?
by Corion (Patriarch) on Aug 08, 2018 at 13:22 UTC

    I'm not sure what you intended with your code, but let's look at what Perl sees:

    >perl -w -MO=Deparse tmp.pl BEGIN { $^W = 1; } sub BEGIN { require 5.01; } use strict 'refs'; BEGIN { $^H{'feature_say'} = q(1); $^H{'feature_state'} = q(1); $^H{'feature_switch'} = q(1); } my(@x) = ('x', 1); my $y = \@x; say $#@ x [1];

    This is the interesting line:

    say $#@ x [1];

    So Perl doesn't see anything regarding @x there, but sees the variable $#@ (the last index of the @@ array, repeated [1] times. Any reference in numerical context evalues to a (large) number. This is what causes the repeated output of -1.

Re: Code Loop?
by hippo (Bishop) on Aug 08, 2018 at 13:30 UTC

    The code can be shortened to simply:

    use 5.010; say $#@x[1];

    Since this compiles even with strict you know that you've done something odd. Corion's explanation is spot on.

      It would be nice to have a strict feature to catch such special variable "zombies", but I'm not sure how to implement it.

      Point is that $@ is a special global package variable, with the glob *main::@ , hence this glob has slots for an array, hash, function,... without being declared.

      like

      D:\Users\lanx>perl -E "use strict; say @@" D:\Users\lanx>perl -E "use strict; say *@" *main::@

      IMHO in at least 95% of the cases these slots are used accidentally.

      Some use them intentionally, but could activate a pragma in these cases. °

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      °) dunno many obfuscators who use strict anyway ;-)

        You could poison them with a tie to catch uses at runtime:

        package Tie::Poison; sub TIESCALAR { ... } sub TIEARRAY { ... } sub FETCH { my $var = tied $_[0]; die "Prohibited variable '$$var' used"; } package unusual_variable_names; our @unusual = qw( @@ @$ ... ); sub unimport { for my $name (@unusual) { no strict 'refs'; tie @{ $name }, 'Tie::Poison', $name; }; }; ... package main; no unusual_variable_names;
      Ahhh, so it's $#@ (as Corion says) times the (random) address of an anonymous array containing the 1?
        > times the (random) address of an anonymous array containing the 1?

        yes since x is imposing numeric context on it's RHS

        D:\>perl -E "say [1]; say 0+[1]" ARRAY(0x24e6d8) 2418704

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: Code Loop?
by LanX (Saint) on Aug 08, 2018 at 13:30 UTC
    your last line looks ill, and is already sufficient to reproduce the issue

    D:\>perl -e "print $#@x[0];" -1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1 +-1-1-1-1-1 -1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1 +-1-1-1-1-1 -1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1 +-1-1-1-1-1 -1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1 +-1-1-1-1-1 -1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1 +-1-1-1-1-1 -1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1 +-1-1-1-1-1 -1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1 +-1-1-1-1-1 ...

    and it only appears with the "variable" x.

    EDIT: saw Corion's post in the meantime which explains it fully, see x in perlop#Multiplicative-Operators.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: Code Loop?
by bitman (Scribe) on Aug 08, 2018 at 13:25 UTC
    Interesting?
    use 5.010; my @x = ("x" => 1); my $y = \@x; my $z= $#@x[1]; say length $z;
    returns 22653312 (or other "random" large number) So not a loop as such.