Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Re: How to safely use $_ in a library function?

by vsespb (Hermit)
on Sep 17, 2013 at 12:47 UTC ( #1054431=note: print w/ replies, xml ) Need Help??


in reply to How to safely use $_ in a library function?

That's widely used pattern (1):

package MyLib; our $MyLibrarysGlobalCallStackInformation; sub myfunc1 { local $MyLibrarysGlobalCallStackInformation = $somedata; myfunc2(); } sub myfunc2 { # use $MyLibrarysGlobalCallStackInformation here }
Another approach (2) would be pass data directly to functions.
package MyLib; sub myfunc1 { myfunc2($somedata); } sub myfunc2 { my ($somedata) = @_; # use $somedata here }
Always use (2), if possible.
Usually you need (1) when writing some kind of fancy DSL.
For you case "goto &sub", you probably can hack something like this:
package MyLib; sub myfunc1 { my (@args) = @_; return myfunc2(@args, $somedata); #instead of goto &myfunc2 } sub myfunc2 { my ($arg1, $arg2, $arg3, $somedata) = @_; if (defined $somedata) { .. # we got there from myfunc1 } }


Comment on Re: How to safely use $_ in a library function?
Select or Download Code
Re^2: How to safely use $_ in a library function?
by perl-diddler (Hermit) on Sep 17, 2013 at 15:18 UTC
    FWIW, saving, restoring and not interfering w/context is important, as is speed, though perhaps the call/return vs. goto isn't that much difference given other functionality, it does change the call stack and make detecting context issues in main function more complicated.

    Some of the code:

    ... use warnings; use warnings FATAL => qw(redefine closure); use Types; use Scalar::Util qw(looks_like_number); use constant CLASS => __PACKAGE__; use Want; sub _Var ($$$;$) :lvalue { # Wrkhorse code for manufc +trd Vars my ($__, $p, $vn, $wa)=@$_; # vn=varname our $_=$__; # must not trash '$_ +' my $c = ref $p || $p; my $rfv = ref $p->{$vn}; # rfv=ref(type) of var my $addrof; if ($wa && $wa eq 'α') { $wa=undef, $addrof=1 } my $arg = $_[0]; return $p->{$vn}=want('ASSIGN') if want(qw(LVALUE ASSIGN)); if (@_ && !$addrof) { # arg for "setter" my $rfa = ref $arg; # ref of the arg if ( !defined($p->{$vn}) or !defined $arg ){ # either undef $p->{$vn} = $arg; } elsif ($rfv eq ARRAY) { ## if type(var)==ARRAY, +1 param my ($index, $ap) = (shift, $p->{$vn}); if ($p->{':pusharray'} or ( !looks_like_number($index) || not( (defined $wa) || @_) )) { push @{$p->{$vn}}, ($index); ## convert to "push" return $index; ## return pushed val +ue } else { $p->{$vn}[$index] = $_[0] if @_; return $p->{$vn}[$index]; } } elsif ($rfv eq HASH) { my $subvar = shift; ## 1 var w/hash is is +a key $p->{$vn}{$subvar} = $_[0] if @_; ## another? =>assign +value return $p->{$vn}{$subvar}; } else { if (length $rfv && $rfv ne $rfa ) { ## incompat assignment warn P "Warning: var type redefined from \"%s\" to \"%s\"", $rfv, $rfa; } $p->{$vn} = $_[0]; ## assignment is default } } # how to return results? (belo +w) if ($rfv eq ARRAY ) { if (defined($wa)) { # arrays special $wa? @{$p->{$vn}} : $addrof ? \$p->{$vn} : $p->{$vn}; } } elsif ($rfv eq HASH ) { $p->{$vn} } elsif ($addrof) { return $p->{$vn} } else { return $p->{$vn}; } } sub varname ($) { substr $_[0], (1+rindex $_[0],':') } sub _access_maker { #{{{ my $pkg = shift; #var in $_ { my $proc = '# line ' . __LINE__ . ' "' . __FILE__ . "\"\n" . ' { use warnings;use strict; package '.$pkg.'; sub '.$_.' (;$) :lvalue { my $sav = [$_,shift, Data::Vars::varname((caller 0)[3]), wan +tarray]; our $_=$sav; goto &Data::Vars::_Var}; 1}'; eval $proc; $@ and die "Fatal error in $pkg\::Vars\::_access_maker?: $@\n"; } } ## end sub _access_maker }}}
    The "Types" module is fairly simple and has a bunch of functions to allow some ease-of-use code like:
    sub ARRAY (;*) { my $p = $_[0]; return @_ ? (ref $p && (1+index($p, '::ARRAY')? 1:0) : 'ARRAY' }
    I.e. it allows one to
    my $ptr=[]; say ARRAY if ARRAY $ptr;
    (with a definition for all the types -- which might explain some syntax issues in the _Var sub)

    Given that perl's not re-entrant with it's use of '$_' anyway, I suppose that using some "global var" to pass the name isn't going to be much worse.

    I'm not sure how local would help or work w/goto, though it would help w/they nested call case.

    Given that I pass most of my needed context from the named func to the generic, I likely no longer have a great need to not nest the calls, though conceptually (and historically), more of the the code for '_Var' was in the named function. There has been a fear of losing the caller's context (stuff accessible on call stack as well as 'wantarray' usage), but most of that may already be encapsulated.

    I had hoped that more context saving of $_ went on in perl than does, but that it doesn't, might make my concerns moot. *sigh*.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (11)
As of 2014-08-22 09:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (153 votes), past polls