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

I was under the impression that @_ would be passed to functions that were called with no arguments, like shift. This rings true except in the case of calling shift in package main, outside of a subroutine where it will shift of @ARGV. Why does it do this, and how can I get shift to work on @_ without copying @_ to @ARGV and not supplying arguments to shift? Or is this possible? Here is the code I've been playing with:
#!/usr/bin/perl -w use strict; @_ = qw( hello world ); ### prints everything in @ARGV but nothing in @_ while(my $d = shift) { print "$d\n"; } ### prints nothing because @ARGV is empty ### doesn't even print @_ contents while(my $n = shift) { print "$n\n"; }

Replies are listed 'Best First'.
Re: @_ the default variable?
by arturo (Vicar) on Sep 14, 2001 at 22:26 UTC

    Outside of a *subroutine*, the default variable for list operations is @ARGV. Inside a subroutine, it's @_. Since none of your code occurs inside a subroutine, it's all attempting to operate on @ARGV.

    Note, though, that while @_ is a respectable global, the @_ your subroutine sees is local to the subroutine. So unless you *explicitly* pass arguments to the subroutine, what you set @_ outside the subroutine won't make any valuables (update or, indeed, *values* =) available to the subroutine. i.e. :

    sub jah { while (my $d = shift) { print "$d\n"; } } @_ = qw(foo bar bat); jah(); # produces no output jah(qw(foo bar bat)); # produces output

    HTH

    perl -e 'print "How sweet does a rose smell? "; chomp ($n = <STDIN>); +$rose = "smells sweet to degree $n"; *other_name = *rose; print "$oth +er_name\n"'

      but &jah; would produce output.

Re: @_ the default variable?
by wog (Curate) on Sep 14, 2001 at 22:35 UTC
    @_ is only passed unchanged to functions called using a prefixing & and no () (e.g. &func). However shift is not really a function. That means you cannot call it like &shift. Shift also takes its arguments in a special way so the & syntax would not even make sense, because & ignores prototypes (which are needed to obtain this "special" treatment of arguments from perl code.)

    arturo is mostly correct about what shift defaults to, but note that there are exceptions (that you are unlikely to encounter anytime soon) where shift will take @ARGV by default within a subroutine. See the docs for more details.

      If shift "is not really a function", what is it? And I thought only *subroutines* were called with &. shift certainly isn't a subroutine.
        The words subroutine and function are often used interchangably in perl. (Even perlsub does it!) What I meant by calling shift "not really a function" was that it is very unlike the functions you define in your code, which have a symbol table entry and thus are associated with a package, can have coderefs be taken of them, and be aliased to other names at the symbol table entry, or imported into other packages, in addition to being callable by the & syntax.
Re: @_ the default variable?
by chromatic (Archbishop) on Sep 14, 2001 at 22:32 UTC
    If you want shift to work on an array, tell it to do so explicitly. There are ways around this by mangling the symbol table, but it's bad karma in this case. Your best bet is to do exactly what you said you don't want to do, and type three extra characters.

    my $n = shift @_;

Re: @_ the default variable?
by HamNRye (Monk) on Sep 15, 2001 at 00:18 UTC

    Really, I do not recommend explicitly defining the @_ var, but I hope it is just for example purposes.

    So in that case....

    #! /usr/bin/perl -w use strict; @_ = qw( Lucy, I'm home! ); sub main { while(my $d = shift) { print "$d\n"; } } &main;

    You can use this if it really upsets you.

    However, assuming your code is not just an example, why in the world are you using the @_ array??? And if your not explicitly defining something to @_, there should not be a variable to read in the main. The package main should always be called first on program execution, and should have @ARGV, and the variables you assigned (globally...). (Side note, yes, I know other built-ins are there, but these are really the vars he needs to deal with.)

    Dont just think of @_, $_, etc, as "default variables", but more as pronouns. "These are as bad as it." Is not a proper sentence, and a worse program. "These are apples, and it is an orange. These cannot compare to it." Now the sentence makes no sense for a reason other than bad grammar.

    So from what I can tell, you're doing something you shouldn't, and perl is making you type three more charachters... Whatta language.

    What would happen to this:

    #!/usr/bin/perl -w use strict; @_ = qw( hello world ) @other = qw( hasta la vista baby ) sub main { while(my $d = shift) { print "$d\n"; # Are we coming or going? } } &main;

    The code actually reads the @_ array, which it should, but more importantly, you can't tell if you're coming or going just from reading it.

    Bad monky...

    ~Hammy

Re: @_ the default variable?
by archen (Pilgrim) on Sep 15, 2001 at 01:54 UTC
    no offence, but you might consider picking up a book on Perl. From your question it seems like you aren't overly familiar with Perl. Believe me, a good book as a reference can save you quite a few headaches as Perl has many intracasies about what function does what under what context.
Re: @_ the default variable?
by n0mad (Initiate) on Sep 16, 2001 at 17:12 UTC
    In main it uses @ARGV as the standard variable for shift because shift without any parameters is used to get arguments given to a function, and the arguments given to 'main' are the command line parameters i.e. @ARGV. So @ARGV is the most logical choice for this.

    -n0mad-