I looked up a few answers dealing with this warning, but neither did they help me, nor do I truly understand what Perl is doing here at all. Here's what I WANT it to do:
sub outerSub {
my $dom = someBigDOM;
...
my $otherVar = innerSub();
return $otherVar;
sub innerSub {
my $resultVar = doStuffWith($dom);
return $resultVar;
}
}
So basically, I have a big DOM object stored in $dom that I don't want to pass along on the stack if possible. In outerSub, stuff is happening that needs the results from innerSub. innerSub needs access to $dom. When I do this, I get this warning "Variable $dom will not stay shared".
What I don't understand:
Does this warning concern me here? Will my intended logic work here or will there be strange things happening?
If it doesn't work as intended: is it possible to do that? To make a local var visible to a nested sub? Or is it better to just pass it as a parameter? Or is it better to declare an "our" variable?
If I push it as a parameter, will the whole object with all its data (may have several MB) be pushed on the stack? Or can I just pass something like a reference? Or is Perl handling that parameter as a reference all by itself?
In "Variable $foo will not stay shared" Warning/Error in Perl While Calling Subroutine, someone talks about an anonymous sub that will make this possible. I did not understand how that works, never used anything like that.
I do not understand that explanation at all (maybe cause English is not my first language): "When the inner subroutine is called, it will see the value of the outer subroutine's variable as it was before and during the first call to the outer subroutine; in this case, after the first call to the outer subroutine is complete, the inner and outer subroutines will no longer share a common value for the variable.":
What does "the first call to the outer subroutine is complete? mean"
I mean: first I call the outer sub. The outer sub calls the inner sub. The outer sub is of course still running. Once the outer sub is complete, the inner sub will be finished as well. Then how does any of this still apply when the inner sub is already finished? And what about the "first" call? When is the "second" call happening... sorry, this explanation confuses me to no end.
Sorry for the many questions. Maybe someone can at least answer some of them.
In brief, the second and later times outerSub is called will have a different $dom variable than the one used by innerSub. You can fix this by doing this:
{
my $dom;
sub outerSub {
$dom = ...
... innerSub() ...
}
sub innerSub {
...
}
}
or by doing this:
sub outerSub {
my $dom = ...
*innerSub = sub {
...
};
... innerSub() ...
}
or this:
sub outerSub {
my $dom = ...
my $innerSub = sub {
...
};
... $innerSub->() ...
}
All the variables are originally preallocated, and innerSub and outerSub share the same $dom. When you leave a scope, perl goes through the lexical variables that were declared in the scope and reinitializes them. So at the point that the first call to outerSub is completed, it gets a new $dom. Because named subs are global things, though, innerSub isn't affected by this, and keeps referring to the old $dom. So if outerSub is called a second time, its $dom and innerSub's $dom are in fact separate variables.
So either moving the declaration out of outerSub or using an anonymous sub (which gets freshly bound to the lexical environment at runtime) fixed the problem.
You need to have an anonymous subroutine to capture variables:
my $innerSub = sub {
my $resultVar = doStuffWith($dom);
return $resultVar;
};
Example:
sub test {
my $s = shift;
my $f = sub {
return $s x 2;
};
print $f->(), "\n";
$s = "543";
print $f->(), "\n";
}
test("a1b");
Gives:
a1ba1b
543543
If you want to minimize the amount of size passing parameters to subs, use Perl references. The drawback / feature is that the sub could change the referenced param contents.
my $dom = someBigDOM;
my $resultVar = doStuffWith(\$dom);
sub doStuffWith {
my $dom_reference = shift;
my $dom_contents = $$dom_reference;
#...
}
Following http://www.foo.be/docs/perl/cookbook/ch10_17.htm , you should define a local GLOB as follows :
local *innerSub = sub {
...
}
#You can call this sub without ->
innerSub( ... )
Note that even if warning is displayed, the result stay the same as it should be expected : variables that are not defined in the inner sub are modified in the outer sub scope. I cannot see what this warning is about.
Related
My program creates an object, which, in turn, creates another object
MainScript.pm
use module::FirstModule qw ($hFirstModule);
$hFirstModule->new(parametres);
$hFirstModule->function();
FirstModule.pm
use Exporter ();
#EXPORT = qw($hFirstModule);
use module::SecondModule qw ($hSecondModule);
sub new {
my $className = shift;
my $self = { key => 'val' };
bless $self, $classname;
return $self;
}
sub function{
$hSecondModule->new(parametres);
#some other code here
}
I want to acces $hSecondModule from MainScript.pm.
It depends.
We would have to see the actual code. What you've shown is a bit ambiguous. However, there are two scenarios.
You can't
If your code is not exactly like what you have shown as pseudo-code, then there is no chance to do that. Consider this code in &module1::function.
sub function {
my $obj = Module2->new;
# ... more stuff
return;
}
In this case, you are not returning anything, and the $obj is lexically scoped. A lexical scope means that it only exists inside of the closest {} block (and all blocks inside that). That's the block of the function sub. Once the program returns out of that sub, the variable goes out of scope and the object is destroyed. There is no way to get to it afterwards. It's gone.
Even if it was not destroyed, you cannot reach into a different scope.
You can
If you however return the object from the function, then you'd have to assign it in your script, and then you can access it later. If the code is exactly what you've shown above, this works.
sub function {
my $obj = Module2->new;
# nothing here
}
In Perl, subs always return the last true statement. If you don't have a return and the last statement is the Module2->new call, then the result of that statement, which is the object, is returned. Of course it also works if you actually return explicitly.
sub function {
return Module2->new;
}
So if you assign that to a variable in your script, you can access it in the script.
my $obj = module1->function();
This is similar to the factory pattern.
This is vague, but without more information it's impossible to answer the question more precicely.
Here is a very hacky approach that takes your updated code into consideration. It uses Sub::Override to grab the return value of the constructor call to your SecondModule thingy. This is something that you'd usually maybe do in a unit test, but not in production code. However, it should work. Here's an example.
Foo.pm
package Foo;
use Bar;
sub new {
return bless {}, $_[0];
}
sub frobnicate {
Bar->new;
return;
}
Bar.pm
package Bar;
sub new {
return bless {}, $_[0];
}
sub drink {
return 42; # because.
}
script.pl
package main;
use Foo; # this will load Bar at compile time
use Sub::Override;
my $foo = Foo->new;
my $bar; # this is lexical to the main script, so we can use it inside
my $orig = \&Bar::new; # grab the original function
my $sub = Sub::Override->new(
"Bar::new" => sub {
my $self = shift;
# call the constructor of $hSecondModule, grab the RV and assign
# it to our var from the main script
$bar = $self->$orig(#_);
return $bar;
}
);
$foo->frobnicate;
# restore the original sub
$sub->restore;
# $bar is now assigend
print $bar->drink;
Again, I would not do this in production code.
Let's take a look at the main function. It first creates a new Foo object. Then it grabs a reference to the Bar::new function. We need that as the original, so we can call it to create the object. Then we use Sub::Override to temporarily replace the Bar::new with our sub that calls the original, but takes the return value (which is the object) and assigns it to our variable that's lexical to the main script. Then we return it.
This function will now be called when $foo->frobnicate calls Bar->new. After that call, $bar is populated in our main script. Then we restore Bar::new so we don't accidentally overwrite our $bar in case that gets called again from somewhere else.
Afterwards, we can use $bar.
Note that this is advanced. I'll say again that I would not use this kind of hack in production code. There is probably a better way to do what you want. There might be an x/y problem here and you need to better explain why you need to do this so we can find a less crazy solution.
I have this perl object. After the object is instantiated, I'm trying to add a new method to the object within a loader method, that can then be called later.
I've tried a whole bunch of stuff that hasn't worked. Examples include:
sub loader {
my ($self) = #_;
sub add_me {
my ($self, $rec) = #_
warn "yayyyyyy";
return $rec;
}
#here are the things I've tried that dont work:
# &{$self->{add_me}} = \&add_me;
# \&{$self->{add_me}} = \&add_me;
# assuming the class definition is in Holder::Class try to add it to symblol table
# *{Holder::Class::add_me} = \&add_me;
}
EDIT:
The reason that I need to do this is I'm adding a hook in my code where the user of my software will have the ability to inject their own sub to edit a data structure as they will.
To do this, they will be able to edit a secondary file that will only contain one sub and get the data structure in question passed in, so something like:
sub inject_a_sub {
my ($self, $rec) = #_;
#do stuff to $rec
return $rec;
}
then inside my original object upon its instantiation, I check to see if the above mentioned file exists, and if so read its contents and eval them. Lastly, I want to make the eval'd code which is just a sub, a method of my object. To be precise, my object is already inheriting a method called do_something and i want to make the sub read in by the eval override the do_something method being inherited so that when called the sub from the external file runs.
its a weird problem :/
and it hurts me :(
Obi wan kenobi you're my only hope!
Cheers!
If you just want to attach functionality to a specific object, and don't need inheritance, you can store a code ref in the object and call it.
# Store the code in the object, putting it in its own
# nested hash to reduce the chance of collisions.
$obj->{__actions}{something} = sub { ... };
# Run the code
my #stuff = $obj->{__actions}{something}->(#args);
Problem is, you need to check that $obj->{__actions}{something} contains a code reference. What I would suggest is to wrap a method around this procedure.
sub add_action {
my($self, $action, $code) = #_;
$self->{__actions}{$action} = $code;
return;
}
sub take_action {
my($self, $action, $args) = #_;
my $code = $self->{__actions}{$action};
return if !$code or ref $code ne 'CODE';
return $code->(#$args);
}
$obj->add_action( "something", sub { ... } );
$obj->take_action( "something", \#args );
If you already know the class name you want to inject a method into, write the subroutine as normal but use the fully qualified name.
sub Some::Class::new_method {
my $self = shift;
...
}
Note that any globals inside that subroutine will be in the surrounding package, not in Some::Class. If you want persistent variables use state inside the subroutine or my outside the subroutine.
If you don't know the name at compile time, you'll have to inject the subroutine into the symbol table, so you were close with that last one.
sub inject_method {
my($object, $method_name, $code_ref) = #_;
# Get the class of the object
my $class = ref $object;
{
# We need to use symbolic references.
no strict 'refs';
# Shove the code reference into the class' symbol table.
*{$class.'::'.$method_name} = $code_ref;
}
return;
}
inject_method($obj, "new_method", sub { ... });
Methods in Perl are associated with a class, not an object. In order to assign a method to a single object, you have to put that object into its own class. Similar to the above, but you have to create a subclass for every instance.
my $instance_class = "_SPECIAL_INSTANCE_CLASS_";
my $instance_class_increment = "AAAAAAAAAAAAAAAAAA";
sub inject_method_into_instance {
my($object, $method_name, $code_ref) = #_;
# Get the class of the object
my $old_class = ref $object;
# Get the special instance class and increment it.
# Yes, incrementing works on strings.
my $new_class = $instance_class . '::' . $instance_class_increment++;
{
# We need to use symbolic references.
no strict 'refs';
# Create its own subclass
#{$new_class.'::ISA'} = ($old_class);
# Shove the code reference into the class' symbol table.
*{$new_class.'::'.$method_name} = $code_ref;
# Rebless the object to its own subclass
bless $object, $new_class;
}
return;
}
I left out the code to check whether or not the instance has already had this treatment by checking if its class matches /^${instance_class}::/. I leave that as an exercise for you. Creating a new class for every object is not cheap and will cost memory.
There are valid reasons to do this, but they are exceptional. You should really, really question whether you should be doing this sort of monkey patching. In general, action at a distance should be avoided.
Can you accomplish the same thing using a subclass, delegation or role?
There already exist Perl OO systems which will do this for you and much much more. You should be using one. Moose, Moo (via Role::Tiny) and Mouse can all add roles to an instance.
Is it better to pass args to recursive function or let dynamic scope deal with it?
sub rec {
my ($arg1, $arg2 ..) = (#_);
..
rec(..);
}
or rather:
sub main {
our ($arg1, $arg2 ..) = (#_);
sub rec {
my $arg1 = shift;
.. # use $args > 1
rec($arg1);
}
Since I have several rec subs in main I prefer 2nd option which doesn't require passing vars all the time and reduces amount bloated code. Said that it's probably not efficient because it will go thru every stack frame in order to resolve dynamic scope?
Don't place a named subroutine inside another. This causes problems (although use warnings; will find them). If you want to avoid passing a constant argument to every recursion, I recommend the following instead:
sub recurse {
my ($constant, ...) = #_;
local *_recurse = sub {
my (...) = #_;
...
_recurse(...);
...
};
_recurse(...);
}
(No idea why you used our. I switched back to my.)
Or with a sufficiently new version of Perl (5.16+):
sub recurse {
my ($constant, ...) = #_;
my $_recurse = sub {
my (...) = #_;
...
__SUB__->(...);
...
};
$_recurse->(...);
}
Whatever you do, though, don't do the following as it leaks.
sub recurse {
...
my $_recurse;
$_recurse = sub {
...
$_recurse->(...);
...
};
...
}
(The inner sub references $_recurse which holds a reference to the inner sub, forming a reference cycle and thus a memory leak.)
If you're using a recursive function that relies on global variables, it can almost certainly be recoded as an iterative subroutine that uses locally scoped variables instead.
I would strongly recommend that you always pass variables and return values, and that you rethink the design of your algorithms to use iteration (while loops) versus recursion.
If you add details for your methods, we might be able to suggest an actual implementation. But given the amount of information you've shared, all we can do is advise design theory.
We are trying to build an API to support commit() and rollback() automatically, so that we don't have to bother with it anymore. By researching, we have found that using eval {} is the way to go.
For eval {} to know what to do, I have thought of giving the API an array of functions, which it can execute with a foreach without the API having to intepret anything. However, this function might be in a different package.
Let me clarify with an example:
sub handler {
use OSA::SQL;
use OSA::ourAPI;
my #functions = ();
push(#functions, OSA::SQL->add_page($date, $stuff, $foo, $bar));
my $API = OSA::ourAPI->connect();
$API->exec_multi(#functions);
}
The question is: Is it possible to execute the functions in #functions inside of OSA::ourAPI, even if ourAPI has no use OSA::SQL. If not, would it be possible if I use an array reference instead of an array, given that the pointer would point to the known function inside of the memory?
Note: This is the basic idea that we want to base the more complex final version on.
You are NOT adding a function pointer to your array. You are adding teh return value of calling the add_page() subroutine. You have 3 solutions to this:
A. You will need to store (in #functions) an array of arrayrefs of the form [\&OSA::SQL::add_page, #argument_values], meaning you pass in an actual reference to a subroutine (called statically); and then exec_multi will do something like (syntax may not be 100% correct as it's 4am here)
sub exec_multi {
my ($class, $funcs)= #_;
foreach my $f (#$funcs) {
my ($func, #args) = #$f;
my $res = &$func(#args);
print "RES:$res\n";
}
}
Just to re-iterate, this will call individual subs in static version (OSA::SQL::add_page), e.g. WITHOUT passing the package name as the first parameter as a class call OSA::SQL->add_page would. If you want the latter, see the next solution.
B. If you want to call your subs in class context (like in your example, in other words with the class name as a first parameter), you can use ysth's suggestion in the comment.
You will need to store (in #functions) an array of arrayrefs of the form [sub { OSA::SQL->add_page(#argument_values) }], meaning you pass in a reference to a subroutine which will in turn call what you need; and then exec_multi will do something like (syntax may not be 100% correct as it's 4am here)
sub exec_multi {
my ($class, $funcs)= #_;
foreach my $f (#$funcs) {
my ($func) = #$f;
my $res = &$func();
print "RES:$res\n";
}
}
C. You will need to store (in #functions) an array of arrayrefs of the form [ "OSA::SQL", "add_page", #argument_values], meaning you pass in a package and function name; and then exec_multi will do something like (syntax may not be 100% correct as it's 4am here)
my ($package, $sub, #args) = #{ $functions[$i] };
no strict 'refs';
$package->$sub(#args);
use strict 'refs';
If I understood your question correctly, then you don't need to worry about whether ourAPI uses OSA::SQL, since your main code imports it already.
However, since - in #1B - you will be passing a list of packages to exec_multi as first elements of each arrayref, you can do "require $package; $package->import();" in exec_multi. But again, it's completely un-necessary if your handler call already required and loaded each of those packages. And to do it right you need to pass in a list of parameters to import() as well. BUT WHYYYYYY? :)
I want to put some subs that are within an OO package into an array - also within the package - to use as a dispatch table. Something like this
package Blah::Blah;
use fields 'tests';
sub new {
my($class )= #_;
my $self = fields::new($class);
$self->{'tests'} = [
$self->_sub1
,$self->_sub2
];
return $self;
}
_sub1 { ... };
_sub2 { ... };
I'm not entirely sure on the syntax for this?
$self->{'tests'} = [
$self->_sub1
,$self->_sub2
];
or
$self->{'tests'} = [
\&{$self->_sub1}
,\&{$self->_sub2}
];
or
$self->{'tests'} = [
\&{_sub1}
,\&{_sub2}
];
I don't seem to be able to get this to work within an OO package, whereas it's quite straightforward in a procedural fashion, and I haven't found any examples for OO.
Any help is much appreciated,
Iain
Your friend is can. It returns a reference to the subroutine if it exists, null otherwise. It even does it correctly walking up the OO chain.
$self->{tests} = [
$self->can('_sub1'),
$self->can('_sub2'),
];
# later
for $tn (0..$#{$self->{tests}}) {
ok defined $self->{tests}[$tn], "Function $tn is available.";
}
# and later
my $ref = $self->{tests}[0];
$self->$ref(#args1);
$ref = $self->{tests}[1];
$self->$ref(#args2);
Or, thanks to this question (which happens to be a variation of this question), you can call it directly:
$self->${\$self->{tests}[0]}(#args1);
$self->${\$self->{tests}[1]}(#args1);
Note that the \ gives us a reference to a the subref, which then gets dereferenced by the ${} after $self->. Whew!
To solve the timeliness issue brain d foy mentions, an alternative would be to simply make the {test} a subroutine itself, that returns a ref, and then you could get it at exactly the time you need it:
sub tests {
return [
$self->can('_sub1'),
$self->can('_sub2')
];
}
and then use it:
for $tn (0..$#{$self->tests()}) {
...
}
Of course, if you have to iterate over the refs anyway, you might as well just go straight for passing the reference out:
for my $ref (0..$#{$self->tests()}) {
$self->$ref(#args);
}
Although Robert P's answer might work for you, it has the problem of fixing the dispatch very early in the process. I tend to resolve the methods as late as I can, so I would leave the things in the tests array as method names until you want to use them:
$self->{tests} = [
qw( _sub1 _sub2 )
];
The strength of a dynamic language is that you can wait as long as you like to decide what's going to happen.
When you want to run them, you can go through the same process that Robert already noted. I'd add an interface to it though:
foreach my $method_name ( $obj->get_test_methods )
{
$obj->$method_name();
}
That might even be better as not tying the test to an existing method name:
foreach my $method_name ( $obj->get_test_methods )
{
$obj->run_test_named( $method_name );
}
That run_test_named could then be your dispatcher, and it can be very flexible:
sub run_test_named
{
my( $self, $name ) = #_;
# do anything you want, like in Robert's answer
}
Some things you might want to do:
Run a method on an object
Pass the object as an argument to something else
Temporarily override a test
Do nothing
etc, etc
When you separate what you decide to do from its implementation, you have a lot more freedom. Not only that, the next time you call the same test name, you can do something different.
use lib Alpha;
my $foo = Alpha::Foo->new; # indirect object syntax is deprecated
$foo->bar();
my %disp_table = ( bar => sub { $foo->bar() } );
$disp_table{bar}->(); # call it
You need a closure because you want to turn a method call into an ordinary subroutine call, so you have to capture the object you're calling the method on.
There are a few ways to do this. Your third approach is closest. That will store a reference to the two subs in the array. Then when you want to call them, you have to be sure to pass them an object as their first argument.
Is there a reason you are using the use fields construct?
if you want to create self contained test subs, you could do it this way:
$$self{test} = [
map {
my $code = $self->can($_); # retrieve a reference to the method
sub { # construct a closure that will call it
unshift #_, $self; # while passing $self as the first arg
goto &$code; # goto jumps to the method, to keep 'caller' working
}
} qw/_sub1 _sub2/
];
and then to call them
for (#{ $$self{test} }) {
eval {$_->(args for the test); 1} or die $#;
}