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

Greets,

I guess the title could also be "accessing implicit $_ in subroutine"...

I'm trying to reliably simulate say() in older Perl versions..

sub say { print @_, "\n"; } my @a = qw(1 2 3); # using implicit $_ does not work: say foreach (@a); # ...and of course explicit $_ works. say $_ foreach (@a); # works: say "uncle bob";

How can I get my say() subroutine to use the implied $_?

Thanks,
Henry

Update 1: Perl v5.8.8

Replies are listed 'Best First'.
Re: Reliably simulating 5.10 say()
by BrowserUk (Patriarch) on Feb 08, 2015 at 14:28 UTC

    How about: sub say{ print @_ ? @_ : $_, "\n"; }


    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". I'm with torvalds on this
    In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
      ok, that works, thanks.

      But it leaves me worried that $_ is being used in say() as a global...

      ...or am I needlessly worried here? All the best practices talk about not using $_ since it's a global, and your suggestion uses $_. So the question is, is that $_ referenced in the say() sub a global from the implicit $_ in the mainline loop, or not...?

        But it leaves me worried that $_ is being used in say() as a global...

        You can't "use as a global", you can just "use a global", and you're the one who asked to use $_.

        So the question is, is that $_ referenced in the say() sub a global from the implicit $_ in the mainline loop, or not...?

        Yes, because $_ is a global. Actually, it's a "super global", meaning "$_" refers to the same variable ($::_) no matter which package you're in.

        Note: It is possible to make $_ a lexical, but that feature was also introduced in 5.10, it's experimental, and I don't think it will survive. (A step was already taken by core to avoid using it.)

        So what you get is:

        BEGIN { if ($] < 5.010) { *say = sub { local $\ = "\n"; print @_ ? @_ : $_ }; } else { require feature; feature->import('say'); } }

        There's probably a module that does that.

        But it leaves me worried that $_ is being used in say() as a global...

        That's what $_ is; a global; and it's exactly what the real say does, along with a raft of other built-ins.

        But it's a read-only reference, so it cannot harm anything.

        So the question is, is that $_ referenced in the say() sub a global from the implicit $_ in the mainline loop, or not...?

        I cannot parse the highlighted bit of that sentence.

        Perhaps this will satisfy: There is only one $_ at any given time. It is the global $_.

        Sometimes it is localised implicitely by some constructs (eg. for, while) and sometimes explicitly by user code; but all that means is that a copy of the previous value is kept somewhere and gets restored once the localisation ends.

        Whenever you use $_; you get its current value, regardless of whether it has been localised in one or many previous scopes.


        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". I'm with torvalds on this
        In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

        The best practice of not using globals is like "don't use goto" or "don't do drugs" - the rule exists because the majority of people abuse them. This is one of the cases where you know what you are doing and why - you're not defining a new global, instead you want to use $_ for its intended purpose. So don't worry :-)

        The only minor caveat about $_ might be if someone were using the experimental lexical $_, introduced in Perl 5.10 and made experimental due to various problems in 5.18:

        sub foo { print "<$_>\n" } for (qw/a b/) { foo; for my $_ (qw/x y/) { foo; } } __END__ Use of my $_ is experimental at - line 4. <a> <a> <a> <b> <b> <b>

        But that's a case of "the user got what they were asking for", plus there's the warning about it being experimental.

        P.S. Have you seen Perl6::Say and Say::Compat? And by the way, the former simply does this in its source: @_ = $_ unless @_;

Re: Reliably simulating 5.10 say()
by Athanasius (Archbishop) on Feb 08, 2015 at 14:12 UTC

    Hello hlc, and welcome to the Monastery!

    This is one case where prototypes are actually useful. From perlsub#Prototypes:

    As the last character of a prototype, or just before a semicolon, a @ or a %, you can use _ in place of $: if this argument is not provided, $_ will be used instead.

    Hence:

    #! perl use strict; use warnings; sub say (_) # <-- ADD THIS { print @_, "\n"; } my @a = qw(1 2 3); say for @a;

    Output:

    0:16 >perl 1151_SoPW.pl 1 2 3 0:16 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Unfortunately, the _ prototype was added in 5.10 (check perl5100delta), the same version where say was added.
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      It actually behaves like

      sub say (_) # <-- ADD THIS { local $\ = "\n"; print @_; }
      Thanks, but that gives me the error:
      Not enough arguments for main::say at a.pl line 10, near "say foreach +" Malformed prototype for main::say: _ at a.pl line 13.
        Perhaps it is a relatively new feature. Which version of Perl are you running?

        The same code works for me in Perl 5.14.

        Update: I did not see it before I posted the above, but several people have responded below that it is a feature that was introduced in version 5.10.

        Je suis Charlie.
        It works perfectly for me. Please show the exact code that you tested and gave this error.

        Je suis Charlie.
Re: Reliably simulating 5.10 say()
by CountZero (Bishop) on Feb 08, 2015 at 15:39 UTC
    Or use Say::Compat.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

    My blog: Imperial Deltronics