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

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

Hi all

I'm using sub _() as a means to localise text, eg:

# set current lang to spanish print _('Hello!'); > ¡Hola!
The sub looks like this:

*::_ = sub { return \*_ unless @_; # to handle eg -e _ $Burro::i18n::Current_Lang->maketext( map {$_} @_ ); };

The second line of the sub is to handle uses of the special filehandle _ in (eg):

stat 'foo' && -e _ && -r _;

However, perl 5.8.9 has added this warning: Use of -l on filehandle _. So while the other -X functions can handle a glob reference to the special filehandle, -l can't.

The code below, in Perl 5.8.8 and 5.10.9 prints 1\n three times, meaning that it works correctly. However, in 5.8.9, you get the failures listed in the comments.

use strict; use warnings; open my $fh,'>','foo' or die $!; print $fh 'foo'; close $fh or die $!; symlink 'foo','bar'; # ln -s foo bar BEGIN { *::_ = sub { return \*_ unless @_; }; } { no warnings; print lstat 'bar' && -l _; # '' (incorrect) print "\n"; } print lstat 'bar' && -l _; # Use of -l on filehandle _ print "\n"; local *_; print lstat 'bar' && -l _; # Undefined subroutine &main::_ print "\n";

If I remove the BEGIN block, then both the -l _ and my _() sub work correctly. Similarly, if I load any modules that use -l _ before defining the _() sub, then everything works correctly. However, this is a fragile way of working around the problem - I'd have check any modules that I use for use of lstat.

Is there any way that I can restore the magic to _?

Replies are listed 'Best First'.
Re: Restoring the magic to the _ filehandle in Perl 5.8.9
by JavaFan (Canon) on Jan 27, 2010 at 17:30 UTC
    I'm using sub _() as a means to localise text
    Beside the problem you have with _ having special meaning, the other problem you have is that _ always lives in main. If you would happen to use a module that also defines a sub _, you have a problem.

    As for your question of restoring magic to _, I'm afraid I don't know the question. I've used sub _ myself before, and ran into the problem, and the problem I mentioned above. I now no longer use sub _. sub __ doesn't have the mentioned problems.

      All true. I initially used sub _ because I'd seen it used in Jifty and because it is the standard getttext way of marking text for i18n, and it worked, but yes - playing with magic does have issues.
Re: Restoring the magic to the _ filehandle in Perl 5.8.9
by ikegami (Patriarch) on Jan 27, 2010 at 23:29 UTC

    As you've stated, if you delay the execution of the code, there's no problem. I presume the reason you're using BEGIN is that the code inside will end up in a module. But you're not out of luck. Execution of INIT blocks are delayed until the main script has finished compiling.

    If you change

    BEGIN { *::_ = sub { # Shout to be understood return uc($_[0]); }; }
    to
    BEGIN { INIT { *::_ = sub { # Shout to be understood return uc($_[0]); }; } }

    then the parser won't think the "_" in "-l _" is a function call since there's no function called "_" yet.

    Caveat: Modules loaded after the script has been compiled...

      Good thinking. Unfortunately, other code of mine relies on sub _ being present at compile time: it doesn't immediately localise those phrases, but wraps each phrase in an object which i18n's the phrase on stringification.

      It turns out that, of all the modules I'm using in my app, only File::Find and File::MMagic use -l _, so I may just preload those.

      thanks for the tip, Ikegami

Re: Restoring the magic to the _ filehandle in Perl 5.8.9
by Animator (Hermit) on Jan 27, 2010 at 22:04 UTC

    The statement: 'The code below, in Perl 5.8.8 and 5.10.9 prints 1\n three times' is incorrect and confusing... I'm guessing you are confusing the different versions of perl...

    Running 'the code below':

    • Perl version: 5.006
      Use of uninitialized value in print at t.pl line 24.
      
      Undefined subroutine &main::_ called at t.pl line 28.
      
    • Perl version: 5.008
      Use of -l on filehandle _ at t.pl line 24.
      Use of uninitialized value in print at t.pl line 24.
      
      Undefined subroutine &main::_ called at t.pl line 28.
      
    • Perl version: 5.008008
      Use of -l on filehandle _ at t.pl line 24.
      Use of uninitialized value in print at t.pl line 24.
      
      Undefined subroutine &main::_ called at t.pl line 28.
      
    • Perl version: 5.008009
      Use of -l on filehandle _ at t.pl line 24.
      Use of uninitialized value in print at t.pl line 24.
      
      Undefined subroutine &main::_ called at t.pl line 28.
      
    • Perl version: 5.010000
      1
      1
      1
      
    • Perl version: 5.011003
      1
      1
      1
      
      And the reason is that 5.10 doesn't consider "_" in "-X _" a function call.
      >perl588\bin\perl -MO=Concise -e"sub _; -l _" 7 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 6 <1> ftlink vK/1 ->7 5 <1> entersub[t2] sKS/TARG,1 ->6 - <1> ex-list sK ->5 3 <0> pushmark s ->4 - <1> ex-rv2cv sK/128 ->- 4 <#> gv[*_] s ->5 -e syntax OK >perl589\bin\perl -MO=Concise -e"sub _; -l _" 7 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 6 <1> ftlink vK/1 ->7 5 <1> entersub[t2] sKS/TARG,1 ->6 - <1> ex-list sK ->5 3 <0> pushmark s ->4 - <1> ex-rv2cv sK/128 ->- 4 <#> gv[*_] s ->5 -e syntax OK >perl5100\bin\perl -MO=Concise -e"sub _; -l _" 4 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v:{ ->3 3 <#> ftlink[*_] vR ->4 -e syntax OK