I wrote about Perl variable declaration secrets recently, but there's much more. Perl has a very simple way for passing variables to subs which should be called later.
I really build a lot of code when I stumbled into the callback-arguments-problem first. Some module asks for a callback function and you want to pass one or more custom arguments:
sub run_later {
print $_[0];
}
$obj->some_function(callback => \&run_later);
The - maybe - obvious way doesn't work...
$obj->some_function(callback => \&run_later("foo"));
A sub is some piece of compiled sourcecode starting at a known memory address. A sub-reference (build by prefixing the sub name with \& ) is basically the memory address of the compiled sourcecode. There is no space to store any argument values, because \& just returns the address value and doesn't "build" or "store" anything.
But Perl has a really smart solution (and now we're back to the topic). A sub won't see the private variables of it's caller...
sub foo {
print $bar; # Would fail when use strict is in place and still not print "1" without strict
}
sub baz {
my $bar = 1;
foo();
}
...but it does see the private variables defined at it's creation time. This is commonly used for script- or module-variables:
#!/usr/bin/perl
use strict;
my %settings;
sub foo {
print $settings{bar};
}
Perl doesn't distingush between block types. A file is a block, a sub is a block and the code-to-be-run part of an if condition is also a block. Every block may access the private variables of it's parent(s) and this is the way to solve the original problem:
sub run_later {
print $_[0];
}
$obj->some_function(callback => sub { run_later($obj); } );
The callback is an anonymous sub this time. All subs are basically a memory address, for some of them (the ones we're typically using) also get names, like run_later in the sample. Anonymous subs simply don't have a name (but one might easily add them to the namespace table of a module), but they're still blocks within some parent block and (as the subs using file-private or module-private variables) they see all variables of their parent blocks. The anonymous sub in this sample may use $obj and pass it to the real callback sub.
The sample is a bit wired, because without any additional source, run_later would see $obj directly (both are running in the same parent block). Things change as soon as the $obj->some_function call is done within any other parent block like a for loop.
Noch keine Kommentare. Schreib was dazu