Given a package name $package and a function name from within that package $function, I can create a reference to that function:
my $ref = eval( "\\&${package}::${function}" );
As a complete example:
#!/usr/bin/perl -w
use strict;
package foo;
sub func()
{
print "foo::func\n";
}
package main;
my $package = "foo";
my $function = "func";
my $ref = eval( "\\&${package}::$function" );
$ref->();
I do not particularly like that eval() in there and wonder if the same result could be achieved without eval()?
All you need is this:
my $ref = \&{ "${package}::$name" };
or
my $ref = \&{ $package . "::" . $name };
Using an expression producing the name of a variable where a variable name is expected is called a symbolic reference. These are usually forbidden by use strict; (specifically use strict qw( refs );), but \& is exempt.
Using strings to refer to subroutines is seldom the right way. If you are doing it this way, you are most likely doing something wrong. You can use a code reference to store a reference to a function, in a scalar or hash. The hash allows you to correctly look up code references via string inputs.
use strict;
use warnings;
package foo;
sub func() {
print "inside foo::func (#_)\n";
}
package main;
# use a direct reference, in a scalar variable
my $ref = \&foo::func;
$ref->(1,2,3);
# ...or in a hash
my $pack = "foo";
my $func = "func";
my %table = ( foo => { func => \&foo::func } );
$table{$pack}{$func}->(qw(a b c));
Output:
inside foo::func (1 2 3)
inside foo::func (a b c)
Related
I am trying to undestand OO in Perl. I made the following trivial class:
#/usr/bin/perl
package Tools::Util;
use strict;
use warnings;
my $var;
sub new {
my ($class, $arg) = #_;
my $small_class = {
var => $arg,
};
return bless $small_class;
}
sub print_object {
print "var = $var\n"; #this is line 20
}
1;
And this is a test script:
#!/usr/bin/perl
use strict;
use warnings;
use Tools::Util;
my $test_object = new Tools::Util("Some sentence");
$test_object->print_object();
use Data::Dumper;
print Dumper($test_object);
The result I get is:
Use of uninitialized value $var in concatenation (.) or string at Tools/Util.pm line 20.
var =
$VAR1 = bless( {
'var' => 'Some sentence'
}, 'Tools::Util' );
I can not understand this. I thought that objects in Perl are hashes and so I could access/initialize the member variables using the same names without a $. Why in this case the $var is not initialized but the hash that I Dump contains the value?
How should I use/initialize/handle member variables and what am I misunderstanding here?
$var is lexical class variable, and undefined in your example.
You probably want:
sub print_object {
my $self = shift;
print "var = $self->{var}\n";
}
Perl doesn't handle object methods in quite the same way that you're used to.
Are you familiar with the implicit this argument that many object-oriented languages use? If not, now would be a great time to read up on it.
Here's a five-second introduction that glosses over the details:
//pretend C++
//this function signature
MyClass::MyFunction(int x);
//is actually more like the following
MyClass::MyFunction(MyClass this, int x);
When you access instance members of the class, my_var is equivalent to this.my_var.
In Perl, you get to do this manually! The variable $var is not equivalent to $self->{var}.
Your blessed object is actually a hash reference, and can be accessed as such. When you call $test_object->print_object(), the sub gets the value of $test_object as its first argument. Most Perl programmers handle this like so:
sub my_method {
my $self = shift; #shift first argument off of #_
print $self->{field};
}
With that in mind, you should probably rewrite your print_object sub to match mpapec's answer.
Further reading: perlsub, perlobj
after foo => sub{
...
}
I just stumble upon code like above, which is called after sub foo finishes,
how does that work?
It seems it's not built-in feature of Perl,right?
It's one of the Moose method modifiers.
Method modifiers can be used to add behavior to methods without modifying the definition of those methods.
Out of curiosity, I've tried to do it myself, and got code that works to some extent (no list context, no corner cases etc.).
Perl allows for horrible things.
% perl -wle 'use After; sub foo { $_[0] * 2};
after foo => sub { print $_[0] }; foo(5); foo(6);'
10
12
Here's After.pm. Please don't ever use it.
use warnings;
use strict;
package After;
# make after() available after 'use After;'
use Exporter;
BEGIN {
our #ISA = qw(Exporter);
our #EXPORT = qw(after);
};
# prototype: bareword + sub
sub after (*&) {
my ($name, $code) = #_;
my $caller = caller; # get calling package
# fetch old sub named "name"
# note $oldcode = *{...} is not ehough
my $oldcode;
{
no strict 'refs';
$oldcode = \&{$caller."::".$name};
};
# defined new sub
my $newcode = sub {
my $ret = $oldcode->(#_); # call old sub as is
$code->($ret); # call the after sub
return $ret; # ignore aftersub's ret val
};
# plant new sub into the calling package
# avoid redefinition warnings
{
no strict 'refs';
no warnings 'redefine';
*{$caller."::".$name} = $newcode;
};
};
1;
It is not a builtin feature as others have already stated. For programs that do not use Moose, you can use Class::Method::Modifiers to get these modifiers.
If after is a predeclared subroutine, it would mean that you call that sub, with foo and an anonymous sub as arguments. It does seem a bit odd, though.
=> is equivalent to a comma, so assuming after is a sub, it would mean this:
after('foo', sub { ... });
Sample code:
m1.pm
my $a;
my $b;
sub init {
$a = shift;
$b = shift;
}
sub printab {
print "a = -$a-\n";
print "b = -$b-\n";
}
1;
m2.pm
my $a;
my $b;
sub init {
$a = shift;
$b = shift;
}
1;
test.pl
use strict;
use warnings;
use m1;
use m2;
init('hello', 'world');
printab();
Run:
$ perl test.pl
a = --
b = --
$
What happens is that the init('hello', 'world') call is mapped to m2.pm and initializes the variables ($a and $b) there.
This kind of makes sense, but what I do not understand is why those values are not available in test.pl.
Is there something fundamentally wrong that I am trying to do here? What is the correct way to use two modules with same named subroutines and variables?
How exactly does a Perl use work? It would help if someone could contrast it with C's #include directive.
In Perl, the use keyword is exactly equivalent to the following:
use Mymodule;
#is the same as
BEGIN {
require Mymodule;
Mymodule->import();
}
So if you are not defining an import routine in your code (or inheriting from Exporter), then your modules are not importing anything into test.pl
As Sinan caught, you are not declaring a package in your modules, so they are defaulting to the main package. In that case, all of your subroutines are in main, but the lexical variables (declared with my) are only scoped to the file they are declared in.
So m1 defines sub init and sub printab to which the lexicals $a and $b are in scope. But then when test.pl loads m2, the init routine is overwritten with the new definition, which is not closed around the two lexicals anymore. So it is writing to the package variables $main::a and $main::b instead of the lexicals which printab is bound to.
If you had warnings enabled (which you always should when learning), you would have been warned about the subroutine redefinition.
You should start each of your modules with:
package Some::Package::Name;
use warnings;
use strict;
and then end each module with:
1;
This is because when you use/require a module, it needs to return a true value at the end so that Perl knows it loaded properly.
First, do read perldoc perlmod.
You do not declare a namespace in either module, so everything is in the main namespace. Declare package m1; in m1.pm and package m2; in m2.pm.
At the very least, you should implement an import method (or inherit the one Exporter provides) so that programs that use modules can decide what to import from where.
It also seems to me that you are exploring around the edges of OO.
Further:
Avoid using $a and $b as variable names because it is easy to confuse them with the package variables $a and $b used by sort.
Don't use lower case module names: They are reserved for pragmata.
A minimal implementation (all in one file for testing convenience) looks like this:
package My::M1;
use strict; use warnings;
sub new { my $class = shift; bless { #_ } => $class }
sub a {
my $self = shift;
my ($v) = #_;
$self->{a} = $v if #_;
return $self->{a};
}
sub b {
my $self = shift;
my ($v) = #_;
$self->{b} = $v if #_;
return $self->{b};
}
package My::M2;
use strict; use warnings;
use base 'My::M1';
sub printtab {
my $self = shift;
for my $x (qw(a b)) {
printf "%s = -%s-\n", $x, $self->$x;
}
}
package main;
my $m = My::M2->new(a => 'hello', 'b' => 'world');
$m->printtab;
printab() is defined in the file m1.pm and only has access to the $a and $b variables that are scoped to that file. The variables $a and $b in m2.pm are scoped to that file, and they are different variables than the $a and $b in m1.pm.
init() sets the variables scoped in m2.pm (because that's the last place the &init function was defined) so it is not setting the same variables that printab() will be trying to print.
I know it is possible to use a variable as a variable name for package variables in Perl. I would like to use the contents of a variable as a module name. For instance:
package Foo;
our #names =("blah1", "blah2");
1;
And in another file I want to be able be able to set the contents of a scalar to "foo" and then access the names array in Foo through that scalar.
my $packageName = "Foo";
Essentially I want to do something along the lines of:
#{$packageName}::names; #This obviously doesn't work.
I know I can use
my $names = eval '$'. $packageName . "::names"
But only if Foo::names is a scalar. Is there another way to do this without the eval statement?
To get at package variables in package $package, you can use symbolic references:
no strict 'refs';
my $package = 'Foo';
# grab #Foo::names
my #names = #{ $package . '::names' }
A better way, which avoids symbolic references, is to expose a method within Foo that will return the array. This works because the method invocation operator (->) can take a string as the invocant.
package Foo;
our #names = ( ... );
sub get_names {
return #names;
}
package main;
use strict;
my $package = 'Foo';
my #names = $package->get_names;
Strict checking is preventing you from using a variable (or literal string) as part of a name, but this can be disabled locally:
my #values;
{
no strict 'refs';
#values = #{"Mypackage"}::var;
}
How could I access the symbol table for the current package an object was instantiated in? For example, I have something like this:
my $object = MyModule->new;
# this looks in the current package, to see if there's a function named run_me
# I'd like to know how to do this without passing a sub reference
$object->do_your_job;
If in the implementation of do_your_job I use __PACKAGE__, it will search in the MyModule package. How could I make it look in the right package?
EDIT:I'll try to make this clearer. Suppose I have the following code:
package MyMod;
sub new {
return bless {},$_[0]
}
sub do_your_job {
my $self = shift;
# of course find_package_of is fictional here
# just for this example's sake, $pkg should be main
my $pkg = find_package_of($self);
if(defined &{ $pkg . '::run_me' }) {
# the function exists, call it.
}
}
package main;
sub run_me {
print "x should run me.\n";
}
my $x = MyMod->new;
# this should find the run_me sub in the current package and invoke it.
$x->do_your_job;
Now, $x should somehow notice that main is the current package, and search it's symbol table. I tried using Scalar::Util's blessed , but it still gave me MyModule instead of main. Hopefully, this is a bit clearer now.
You just want caller
caller tells you the package from which it was called. (Here I added some standard perl.)
use Symbol qw<qualify_to_ref>;
#...
my $pkg = caller;
my $symb = qualify_to_ref( 'run_me', $pkg );
my $run_me = *{$symb}{CODE};
$run_me->() if defined $run_me;
To look it up and see if it's defined and then look it up to call it would duplicate it as standard perl doesn't do Common Subexpression Elimination, so you might as well 1) retrieve it, and 2) check definedness of the slot, and 3) run it if it is defined.
Now if you create an object in one package and use it in another, that's not going to be too much help. You would probably need to add an additional field like 'owning_package' in the constructor.
package MyMod;
#...
sub new {
#...
$self->{owning_package} = caller || 'main';
#...
}
Now $x->{owning_package} will contain 'main'.
See perldoc -f caller:
#!/usr/bin/perl
package A;
use strict; use warnings;
sub do_your_job {
my ($self) = #_;
my ($pkg) = caller;
if ( my $sub = $pkg->can('run_me') ) {
$sub->();
}
}
package B;
use strict; use warnings;
sub test {
A->do_your_job;
}
sub run_me {
print "No, you can't!\n";
}
package main;
use strict; use warnings;
B->test;
Output:
C:\Temp> h
No, you can't!