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;
}
Related
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)
It is possible in perl to call method using package name in variable like this:
my $cls = 'PackageName';
$cls->method()
which calls PackageName->method()
What is the correct syntax to use package variable, e. g. $PackageName::SOME_VAR in the same manner, having package name in $cls variable?
You need to use the following syntax.
use strict;
use warnings;
use feature 'say';
package Foo;
our $bar = 123;
package main;
{
my $package = 'Foo';
no strict 'refs';
say ${"${package}::bar"};
}
The outer ${ ... } is for the reference. The syntax says take the value in the symbol table with the given name as a scalar. The inner ${package} is just the lexical variable $package, with the curly braces {} as a name delimiter.
It's important to turn off strict references for it to work. Remember to do that in the smallest scope possible.
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
I'm new to Perl and I'm learning OOP in Perl right now.
Is there a way without any additional libraries (it is forbidden to use any additional lib) to access variable from one package in another one?
package Class;
my $CONSTANT = 'foo'; # this doesn't work, neither our $CONSTANT ..
# ...
# class methodes
# ...
package main;
print Class::$CONSTANT ."\n";
Your constant declaration is wrong
Constants do not have a $ before their name because they are not variables -- a variable (as implied by the name) contains a value which can vary.
Try this (it uses the constant module but that's included in the default installation:
use constant CONSTANT => "Foo";
Accessing class constants
You can then access them as:
Class::CONSTANT # I suggest NOT using this as 'Class::Constant' is a module name, rename your class to something useful
Or, if you have $obj as an instance of Class:
$obj->CONSTANT;
Sample code showing both access methods
use warnings;
use strict;
package MyClass;
use constant SOME_CONSTANT => 'Foo';
sub new
{
my $type = shift; # The package/type name
my $self = {}; # Empty hash
return bless $self, $type;
}
package main;
print MyClass::SOME_CONSTANT . "\n"; # Prints 'Foo\n'
my $obj = MyClass->new();
print $obj->SOME_CONSTANT; # Prints 'Foo'
And a demo.
Easy mistake to make. Put the sigil in front of the class name, e.g.
print ${Class::CONSTANT} . "\n";
print $Class::CONSTANT . "\n";
In addition constants can be defined using the constant package, e.g.
use constant MY_CONSTANT => 5;
print MY_CONSTANT();
You have to define variable using our.
package Class;
our $CONSTANT = 'foo';
# ...
# class methodes
# ...
package main;
print $Class::CONSTANT ."\n";
Keyword package works as syntactic block, so variable defined using my is not accessible outside this syntax block. You also have to place sigil $ in right place. And of course it is variable, not constant.
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.