Limbic~Region has asked for the wisdom of the Perl Monks concerning the following question:

All,
I looked at the following code for a few minutes before realizing the problem:
#!/usr/bin/perl use strict; use warnings; my @list = map {[qw/foo bar blah baz/]} 1 .. 5; splice(@$, 0, 1) for @list;
I just can't figure out why perl didn't throw any errors or warnings. Running it through perl -MO=Deparse didn't turn up anything. Changing splice(@$, 0, 1) to splice(@$_, 0, 1) produces the correct result. This is AS perl 5.10.0

What am I missing?

Cheers - L~R

Replies are listed 'Best First'.
Re: Is this a bug in splice?
by tilly (Archbishop) on Feb 20, 2008 at 03:11 UTC
    You've somehow successfully manipulated the array @$. I proved it by adding the following snippet of code:
    for my $key (sort keys %main::) { next unless *{$main::{$key}}{ARRAY}; print "$key\n"; }
    Before your splice, I found only +, -, ARGV, INC and _ populated. After your splice you added $. The last array was, of course, empty. But the following code clearly populates it:
    #!/usr/bin/perl use strict; use warnings; my @list = map {[qw/foo bar blah baz/]} 1 .. 5; splice(@$, 0, 1, "hello", "world") for @list; print "@$\n";
    Edit: Simplified my code. I knew there was an easier way to write @{*main::{'$'}{ARRAY}}...

    Update: Upon thinking about it, this behaviour likely falls out of whatever logic makes $$ be recognized as a valid variable name. Because if you can name a variable $, then you should be able to put any sigil you want in front of that $. Or dereference it any way you want.

    This is one of the astounding things about Perl. You start with a piece of behaviour and you say, "WTF?" Then you figure out what it did and you say, "Oh, here is what it did." Then you figure out why it did it and you go, "Oh, that is really quite reasonable for it to do." And suddenly it doesn't seem all that surprising.

      tilly,
      The frustrating thing is that you can't intentionally create @$ without some effort:
      my @$ = 1..4; # issues an error
      On the other hand, if you accidentally use it without declaration - it springs into existence and doesn't throw any errors nor warnings. Even if that is documented behavior, it smells bad (of course, there is probably very good reason for it).

      Cheers - L~R

        Take a look at the error you get. Perl knows that @$ is not a valid name for a lexical variable. So it won't let you declare it with my. But it is a valid global variable name, and Perl recognizes it as such.

        Try declaring it with our. Also see my update to my original response.

        Edit: I said $@ and meant @$. Thanks ysth.

Re: Is this a bug in splice?
by ikegami (Patriarch) on Feb 20, 2008 at 02:32 UTC
    Are you referring to the lack of stricture errors? Quote perlvar,

    Perl identifiers that begin with digits, control characters, or punctuation characters are exempt from the effects of the package declaration and are always forced to be in package main ; they are also exempt from strict 'vars' errors.

      ikegami,
      Ok, so perl thinks I have an array named @$

      This is still frustrating because if I had done

      my @$ = 1..4;
      I would have gotten an error. This behavior still doesn't smell right to me but "oh well".

      Cheers - L~R

        Yes, but for unrelated reasons.
        @$ is not a valid name for a lexical.
        our @$ = 1..4; would not give an error.
        By your logic, splice(@Foo::bar, 0, 1) should give an error because my @Foo::bar = 1..4; gives an error.

Re: Is this a bug in splice?
by BrowserUk (Patriarch) on Feb 20, 2008 at 02:47 UTC

      You're assuming "@$," means "@{$,}" but it apparently means "@{$},".