Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re^3: $_ functions vs argument-using functions

by LanX (Canon)
on Sep 09, 2013 at 19:12 UTC ( #1053084=note: print w/ replies, xml ) Need Help??


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

> (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.


Comment on Re^3: $_ functions vs argument-using functions
Select or Download Code
Re^4: $_ functions vs argument-using functions
by pldanutz (Acolyte) on Sep 09, 2013 at 19:23 UTC
    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.

      It's documented, see perlglossary for "expression".

      The point is you can't reuse this coding style very often, so better avoid it.

      You can write sub func (&@) { } to use block syntax. like in func {shift()+1 } 1..10

      Or you can directly pass function references  f(\&g(\&h),1..10)

      or anonymous subs  f(sub {...},1..10)

      without using prototypes at all.

      But Perl won't allow you to rewrite anything like func EXPR, LIST acting like map does.

      And as I said have a look into HOP.

      Please understand that I won't go further into details of a theoretical discussion, I'd rather prefer to see a real use case from you such that we can recommend the Perl way to do it.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

Re^4: $_ functions vs argument-using functions
by tobyink (Abbot) on Sep 09, 2013 at 21:26 UTC

    "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
      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

      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.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1053084]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (18)
As of 2014-12-19 18:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (91 votes), past polls