in reply to $_ functions vs argument-using functions

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)

Replies are listed 'Best First'.
Re^2: $_ functions vs argument-using functions
by pldanutz (Acolyte) on Sep 09, 2013 at 19:01 UTC

    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.

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

        Actually the block used by map and grep is not an anonymous function; it's just a block like if and while take. It does have a little overhead because it creates a lexical scope (it can have my variables defined within it); however not as much overhead as an anonymous sub would - calling it doesn't require stack fiddling, localizing @_, etc.

        It's quite easy to confirm it's not an anonymous sub - check how caller and return behave inside a map or grep block, and compare them with what happens in an anonymous sub. return doesn't return from the map block; it returns from the outer sub.

        With non-built-in functions that at first glance seem similar to map and grep (for example, List::Util's first), the block is an anonymous sub, so there is more overhead calling it. But not necessarily as much as you might think; List::Util takes advantage of an interface Perl exposes to XS code called "multicall" allowing it to repeatedly call the same anonymous sub without stack fiddling for each call - it does the stack fiddling just once, and then for each call sets @_ and runs the body of the sub.

        use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
        Yeah. These magic parsing exceptions are clearly not accessible to normal users, especially since the perldoc page doesn't seem to document it at all. How was I supposed to find out about this exception reading the docs?

        In any case, I cannot include a large amount of code in an anonymous block passed to map(). So I guess this sanctions the use of $_-using functions.

      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". ;-)
        Was he really conpletely wrong, because an "except when called with &-sigil" was missing?

        Is it possible to talk about Perl and always mention all special cases???

        Cheers Rolf

        ( addicted to the Perl Programming Language)