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

I realize that @ARGV is a special variable, but I wonder what the rational is for this behavior:
package foo; sub ARGV { print "in foo::ARGV\n" } package main; foo->ARGV;
yields:
Can't locate object method "ARGV" via package "foo" ...

Replies are listed 'Best First'.
Re: ARGV as a sub name?
by chromatic (Archbishop) on Aug 18, 2010 at 20:59 UTC

    B::Deparse reveals all:

    $ perl -MO=Deparse package foo; sub ARGV { print "in foo::ARGV\n" } package main; foo->ARGV; package foo; sub main::ARGV { print "in foo::ARGV\n"; } package main; 'foo'->ARGV; - syntax OK

    I haven't yet found the part of the parser which forces sub ARGV into main::.

      Interestingly enough, if you add use strict (at least on 5.8.9 and 5.10.1) to package foo, B::Deparse does not reveal all, like so:
      package foo; sub BEGIN { require strict; do { 'strict'->import }; } sub ARGV { use strict 'refs'; print "in foo::ARGV\n"; } package main; use strict 'refs'; 'foo'->ARGV;
      (in fact just making sub ARGV not the first line of code after package foo is enough to confuse B::Depase in this.
Re: ARGV as a sub name?
by ikegami (Patriarch) on Aug 18, 2010 at 22:23 UTC

    The special variables are "super global"*, accessible from any namespace without qualification. This is done by making the name of the variable "super global". That means that if $_ is super global, so is array @_, hash %_, sub &_, etc.

    "ARGV" is one of those names. No matter what namespace is current, sub ARGV { } will define &main::ARGV, and ARGV() will call &main::ARGV.

    You can get around that by specifying which package's ARGV you want.

    { package Foo; sub ARGV { print "1\n" } sub Foo::ARGV { print "2\n" } } { package Bar; ARGV(); # 1 Foo::ARGV(); # 2 Foo->ARGV(); # 2 }

    Replace "ARGV" with "_" and you'll get the same results.

    * — Not a technical term :)

Re: ARGV as a sub name?
by james2vegas (Chaplain) on Aug 18, 2010 at 21:00 UTC
    From perlmod:
    In addition, when unqualified, the identifiers STDIN, STDOUT, STDERR, ARGV, ARGVOUT, ENV, INC, and SIG are forced to be in package `main', even when used for other purposes than their built-in ones.

    So when you try and use those as bare subnames, they get forced into main, try main->ARGV instead of foo->ARGV to see the 'in foo:' message. To specifically make an ARGV (or one of the other names forced into main) sub in 'foo', qualify your name, like this:
    sub foo::ARGV { print "in foo::ARGV\n" }
    Now foo->ARGV will do what you expect.
Re: ARGV as a sub name?
by kennethk (Abbot) on Aug 18, 2010 at 20:25 UTC
    Can't shed all that much light on the issue, but I can point out the following from ARGV in perlvar:

    ARGV

    The special filehandle that iterates over command-line filenames in @ARGV . Usually written as the null filehandle in the angle operator <> . Note that currently ARGV only has its magical effect within the <> operator; elsewhere it is just a plain filehandle corresponding to the last file opened by <> . In particular, passing \*ARGV as a parameter to a function that expects a filehandle may not cause your function to automatically read the contents of all the files in @ARGV .

    ARGV: It's more than just an array!

    Update: And if you really want to do what you appear to want to do, running this script:

    #!/usr/bin/perl use strict; use warnings; package foo; sub fake_ARGV { print "in foo::ARGV\n" } no warnings "once"; *foo::ARGV = *foo::fake_ARGV; package main; foo->ARGV; print $ARGV[0];
    does this:

    ~/sandbox$ perl test.pl 'Still here' in foo::ARGV Still here
      That is not required, all is required is this:
      package foo; use strict; sub foo::ARGV { print "in foo::ARGV\n" } package main; foo->ARGV;
Re: ARGV as a sub name?
by Anonymous Monk on Aug 19, 2010 at 05:42 UTC
    OT: that should be "rationale for this behavior".

    Also note that rational is not a noun and that they're pronounced differently: "rational" is something like "RASH-ən-əl" and "rationale" is something like "rash-ən-AL" (rhyming neither with "all" nor "ale", but with the shortened form of "Albert").