Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Lexical $_ in given/when vs. BLOCK arguments

by mbethke (Hermit)
on Oct 25, 2011 at 09:35 UTC ( #933579=perlquestion: print w/ replies, xml ) Need Help??
mbethke has asked for the wisdom of the Perl Monks concerning the following question:

Hi guys,

I just noticed that the given/when construct's way of introducing a lexical $_ plays badly with functions that take BLOCKs such as List::MoreUtils::any. The following does not print anything:

use 5.010; use strict; use warnings; use List::MoreUtils qw/ any /; my $s = "foo"; my @list = ( 1, undef, 2 ); given($s) { when('foo') { say "found undef" if any { ! defined($_) } @list; } }

Within the block, $_ is always 'foo' as it was bound during the block's definition.

Now this must be a known problem, right? For my inner peace, could someone explain me the rationale for making "given" so subtly different from say "for"? And for my productivity, is there a way around it short of "don't use 'given'"?

Thanks very much!

Comment on Lexical $_ in given/when vs. BLOCK arguments
Download Code
Replies are listed 'Best First'.
Re: Lexical $_ in given/when vs. BLOCK arguments
by moritz (Cardinal) on Oct 25, 2011 at 10:02 UTC

      I have to admit I didn't even search because after a look at the trivial code of any() (and pasting it in my script to make sure it's not the fault of some XS foo) I was pretty convinced it can't possibly be the function's fault. It's written exactly as I would do it and as every book I've seen recommends it.

      Thanks to everybody who recommended "our" etc.---I'd only tried local which unsurprisingly didn't work. Still, having to think about something like this is a major PITA, particularly when it's inconsistent and e.g. works with builtins like grep. I think for me it boils down to "given is evil". for/when should do fine as long as there are no continues.

      List::* and similar modules could probably work around that with some bytecode hack as suggested in a reply to the bug but having to introduce such extreme ugliness to restore sane behavior suggests something else needs fixing

      So I think this is at least a documentation bug of given/when. Why the lexical $_ I still don't know; making

      given($foo) { when('bar') { ... } }
      equivalent (well, with some added magic for the last/continue stuff) to
      do { if($foo ~~ 'bar') { ... } }
      would seem to make more sense IMHO. But if it behaves like it does, it should carry a big fat warning saying "If you define any blocks or callbacks within given(), don't expect $_ to behave like everywhere else, use explicit "our" or there will be weeping and gnashing of teeth!!!11!"

        I think for me it boils down to "given is evil".

        I concur. I tried to use given/when on a few occasions and always reverted to something simpler. Altogether just to damn magical for its own good. I seriously doubt I will ever make use of it again.

        I much prefer the simple, reliable semantics of use Switch::Perlish 'C';


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Lexical $_ in given/when vs. BLOCK arguments
by ikegami (Pope) on Oct 25, 2011 at 17:42 UTC

    It's a known problem with lexical $_, but lexical $_ is not a bug. The relevant developers of Perl hadn't yet clued in about this issue when given was added.

Re: Lexical $_ in given/when vs. BLOCK arguments
by Anonymous Monk on Oct 25, 2011 at 09:52 UTC
    Beats me, but you can use $::_ to refer to the global $_

        The old standby local $_; will fail with

        Can't localize lexical variable $_ at junk line 13. (#1) (F) You used local on a variable name that was previously declared + as a lexical variable using "my" or "state". This is not allowed. If +you want to localize a package variable of the same name, qualify it with the package name.

        I think local $_ should just work, for those who can't remember to use our $_;

        At a minimum, I think the perldiag entry for this error should say to use our $_;

        or even any { our $_; ... }

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (13)
As of 2015-07-28 12:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (254 votes), past polls