Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Making variables visible between calls.

by ambs (Pilgrim)
on Dec 12, 2008 at 17:56 UTC ( #729998=perlquestion: print w/replies, xml ) Need Help??

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

Hello.

What I really want (if the code worked as I was expecting):

sub create_f { my $func = shift; return sub { my $var = "xpto"; &$func; } } my $function = create_f( sub { print ">> $var <<\n" } );

I mean, supply a function that uses a variable that is declared outside. Of course I do not want this on this context, this is just my test code.

I do not want to make the variable global to the package.

Any hints?

Thanks! :)

Alberto Simões

Replies are listed 'Best First'.
Re: Making variables visible between calls.
by kennethk (Abbot) on Dec 12, 2008 at 18:24 UTC

    So you want the behavior of a global variable without a global variable? Are you trying to limit access to the value, or are you just trying to create persistent parameters? In either case, sounds like you want to go OOP-esque.

    package Parameters; use strict; use Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(get_var); my $var = "xpto"; sub get_var{ return $var; } 1;

    and then call it as

    use Parameters; print get_var;

    This has the added benefit that $var is completely inaccessible outside of any accessor methods you give the user.

Re: Making variables visible between calls.
by ikegami (Pope) on Dec 12, 2008 at 18:09 UTC
    sub create_f { my $func = shift; return sub { $func->("xpto"); } } my $function = create_f( sub { my $var = shift; print ">> $var <<\n" } );

    It's technically possible using dynamic scoping (local), but that increases coupling. What I presented is a much better alternative.

      Yes, at the moment that is my own solution, but that forces the user to get a set of predefined parameters. It works, but not as clean as I would like it to be to the user. ;)

      Thanks

      Alberto Simões

        A set? No. You could pass a hash or an object.

        Not as clean? Any method of passing arguments without using parameters would be less clean than using parameters.

Re: Making variables visible between calls.
by kyle (Abbot) on Dec 12, 2008 at 18:15 UTC

    Allow the function to take an argument.

    sub create_f { my $func = shift; return sub { my $var = 'xpto'; $func->( $var ); } } my $f = create_f( sub { my $var = shift; print ">> $var <<\n"; } );

    Otherwise, I don't see a way to do it. The sub can't reach outside its scope for variables that aren't global.

    You could cook up something with eval, maybe.

    sub create_f { my $func = shift; return sub { my $var = "xpto"; eval $func; } } my $function = create_f( 'print ">> $var <<\n"' ); $function->(); __END__ >> xpto <<

    I'm not sure if that fits with your real problem or not.

Re: Making variables visible between calls.
by Arunbear (Prior) on Dec 12, 2008 at 18:31 UTC
    You could put the variables into some other package which exists just to hold them e.g.
    #!/usr/bin/perl use strict; use warnings; sub create_f { my $func = shift; return sub { $MyBucket::var = "xpto"; &$func; } } my $function = create_f( sub { print ">> $MyBucket::var <<\n" } ); $function->();
Re: Making variables visible between calls.
by friedo (Prior) on Dec 12, 2008 at 18:12 UTC

    Your anonymous subroutine can't see $var since it's compiled in a lexical scope separate from where it's executed. But it can have values passed into it as arguments.

    sub create_f { my $func = shift; return sub { my $var = "xpto"; $func->( $var ); } } my $function = create_f( sub { print ">> $_[0] <<\n" } ); $function->();

    Update: And if you want to specify the value at runtime, it's as easy as passing it into create_f.

    sub create_f { my $func = shift; my $var = shift; return sub { $func->( $var ); } } my $function = create_f( sub { print ">> $_[0] <<\n" }, 'xpto' ); $function->();

Re: Making variables visible between calls.
by jeffa (Bishop) on Dec 12, 2008 at 18:06 UTC

    How about just this?

    my $function = sub { my $var = 'xpto'; print ">> $var <<\n" }; $function->();

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    

      That doesn't help. I need to let the user define his own function, and give him the possibility to access some pre-defined variables in case he wish to.

      My only possibility at the moment is to force the user defined function to receive a set of predefined parameters. But that will mess up some things later...

      But thanks, anyway ;)

      Alberto Simões

        It sounds like you realy want to pass it a hash. Then just preload the hash with values that it should have access to.

        my $function = sub {my $v = shift; print ">> $v->{var} <<\n" }; my $params = {var => 'exto'}; $function->($params);

        ___________
        Eric Hodges

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (2)
As of 2021-09-17 05:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?