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

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

By $_-using functions, I mean functions that take their argument from the implicit variable $_, instead of relying on "actual" arguments that a sub receives in @_

Some second-order functions (e.g. map, as I learned in map sub to list?) prefer $_-using functions, instead of functions that use their @_ arguments:

Is one style preferred over the other in general? How can I convert between them?

sub f1 ($) { shift(@_) + 1 } sub f2 { $_ + 1 } map (f1($), (10, 20)) # convert f1 to $_-style my $x = f1 (10) # call f1 with an arg # my $y = f2 (10) # won't work, how to use f2??
P.S. How do I even search for stuff like this? I'm sure others must have asked this before.

Replies are listed 'Best First'.
Re: $_ functions vs argument-using functions
by LanX (Saint) on Sep 09, 2013 at 18:58 UTC
    ok, some sources of confusion

    1. Perl has -alas - no function signatures, nothing like sub f($a,$b) {...}
    2. don't use prototypes before you know what you are doing, avoid sub f($) {...}
    3. the default variable $_is not primarily meant for functions.

    see perlsub for subs and prototypes.

    see perlvar (and perlsyn for $_

    see perlfunc for builtin functions

    Cheers Rolf

    ( addicted to the Perl Programming Language)

      I understand that the prototype sub f ($) {} makes sure f is called with exactly one argument. I know I can't have formal args, but can use my ($a, $b) = @_ instead (or shift @_)

      I know what $_ is used for, the way it gets its value in while (<>) and the way it is used implicitly in m/PATTERN/ and chomp. But I see that it can be used instead of function arguments (e.g. map prefers such functions). And I was asking if that was a preferred style.

        > (e.g. map prefers such functions)

        thats a misunderstanding, because the normal (ok nowadays recommended) way to use map is with a block using the default var. So "map prefers blocks"!

        From this point of view writing map { f($_) } 1..3 is the canonical approach!

        But this means overhead, because map calls now two functions in a row (the block means an anonymous function).

        To avoid this, some experts prefer using the EXPR syntax  map f, 1..3 which is magic (which means a parsing exception introduced for DWIM and syntactic sugar).

        Because a bareword in Perl almost always means a function call², if you need the function reference of f you need to write \&f, but some builtins like map and grep magically (sic) accept expressions.

        Since you are replacing the block with f you have to mimic the behaviour to use $_ - a localized global variable - in the function body.¹

        Your problems understanding all of this derive from the fact that you are starting with the rare syntax exceptions.

        Clearer now?

        (BTW: I always wanted to write a cross-manual explaining Perl vs JS, to highlight the details in both languages, but somehow all people told me there is no need... )

        Cheers Rolf

        ( addicted to the Perl Programming Language)

        ¹) The trick with the (_) prototype is rather new, it passes $_ into @_ if an argument is missing.

        ²) opposed to languages like JavaScript where a bare f is ALWAYS the reference of function f(a,b,c){ ... }

        update

        if you are interested in functional programming, try having a look into *Higher Order Perl* - you can download it for free.

        I understand that the prototype sub f ($) {} makes sure f is called with exactly one argument.

        Sorry, but that's not true:

        #!/usr/bin/perl use strict; use warnings; sub f($) { print 'f called with ',0+@_,' arguments: ',join(', ',@_),"\n"; } sub g { print 'via g: '; &f; } f(42); &f(42); &f(); &f(42,99,333); g(42); g(); g(42,99,333);

        Output:

        f called with 1 arguments: 42 f called with 1 arguments: 42 f called with 0 arguments: f called with 3 arguments: 42, 99, 333 via g: f called with 1 arguments: 42 via g: f called with 0 arguments: via g: f called with 3 arguments: 42, 99, 333

        See perlsub for what happens here, and why perl does not complain.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: $_ functions vs argument-using functions
by tobyink (Canon) on Sep 09, 2013 at 21:11 UTC

    Using $_ as the primary method of passing parameters to a function does not seem like good style to me. A common pattern amongst Perl's built-ins though is to pass a parameter, but use $_ when no parameter is passed. A la:

    sub f3 { my $input = @_ ? shift : $_; return $input + 1; }

    If you're using a vaguely recent version of Perl, the underscore prototype makes this simpler (and magically works with lexical $_):

    sub f4 (_) { my $input = shift; return $input + 1; }
    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
Re: $_ functions vs argument-using functions
by Generoso (Prior) on Sep 09, 2013 at 19:04 UTC

    Apologies this answer is for an other question.

Re: $_ functions vs argument-using functions
by Jenda (Abbot) on Sep 10, 2013 at 13:49 UTC
    map (f1($_), (10, 20)) # convert f1 to $_-style my $x = do {local $_ = 10; f2}; # or, if you just want to call that subroutine, f2 for (15);

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.