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


in reply to Re^3: $_ functions vs argument-using functions
in thread $_ functions vs argument-using functions

"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

Replies are listed 'Best First'.
Re^5: $_ functions vs argument-using functions
by LanX (Saint) on Sep 09, 2013 at 21:44 UTC
    Wow, thanks for the info!

    ( learned again something new in the universe of Perl's special cases... ;-)

    update

    so from a performance point of view there is no reason to prefer map f, 1..3 over map { g($_) } 1..3!

    Cheers Rolf

    ( addicted to the Perl Programming Language)

      As I said, the block form does add a little overhead, because it creates a lexical scope. It's very minor though, so it's generally better to go with whatever you think is more readable.

      When you need to micro-optimize a tight loop that gets called millions or billions of times... that's when you start looking at removing unnecessary lexical scopes! The block forms of grep and map can be replaced with the expression forms; if/elsif/else chains can become ternary operator expressions; foreach blocks become statement modifiers; etc.

      use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
Re^5: $_ functions vs argument-using functions
by Laurent_R (Canon) on Sep 09, 2013 at 22:36 UTC

    Very interesting information, indeed. As I am sure many other monks before me and probably others after and in the future, I have tried a couple of years ago to rewrite in Perl a "my_map" and a "my_grep" functions (just for the sake of experimenting). And, if my memory serves me right, I ended up writing a simple anonymous function; then adding a code-ref prototype to my_map was all what was needed to mimic exactly the block syntax of map (getting rid of the sub keyword). So, I also considered the map block to be more or less equivalent to an anonymous function and I actually wrote today, just a few hours ago, in answer to another question of the original poster of this thread, that "the (map) block can be regarded as an anonymous function" (in this thread: map sub to list?). From the functional point of view that I was using, I think it is probably right to put it this way and that I probably don't need to change anything to my formulation, but it is quite interesting to know that from an implementation point of view, there is a significant difference which has an impact on performance. Anyway, thank you for the implementation details, this is very useful to know.