Accessing Moose object in package to be called explicitly outside - perl

for a Moose package, I am trying to create a object in Perl (non-moose) and then trying to access a method outside. Code to explain this situation is here.
package person;
{
use Moose;
sub test {
print "my test print";
}
}
package people {
use person;
my $obj = person->new();
}
$people::obj->test()
I am getting following Error on executing this perl code.
Can't call method "test" on an undefined value at test.pm
Am I missing anything here ?

You never assigned anything to $people::obj. You assigned something to an unrelated lexical var named $obj, a variable that doesn't even exist by the time the program reaches the method call. Lexical vars (e.g. those created by my) are scoped to the innermost curlies in which they are located, which is to say they are only visible (accessible) there.
Fix:
package Person;
{
use Moose;
sub test {
print "my test print";
}
}
package People {
my $obj = person->new();
sub get_person {
return $obj;
}
}
People->get_person->test();
Notes:
Removed use person; which either prevented the program from compiling, or unintentionally executed some potentially-conflicting code.
Lowercase module names are reserved for pragmas.
I could have have changed the lexical variable into a package variable, but using global variable is a bad practice. Using a method (or sub) can make things a lot easier in the future.
Be careful putting multiple packages/classes in one file. There are pitfalls.

If you do want to use $obj as a global variable and use it outside the package, you have to define it as such with our. Changing
my $obj = person->new();
to
our $obj = person->new();
and your script works. But using globals - even via getters as ikegami proposed - is often a bad idea.

Related

Why not simply use __PACKAGE__ when creating a new Perl module?

I wish I knew the reference or document that told me that this is the best way to create a new object in Perl:
sub new {
my $package = shift;
my $class = ref($package) || $package
This is how I've been creating objects for years but now I'm wondering why go to the trouble? With the exception of some edge cases why not simply do the following:
sub new {
shift; # get rid of the object or package name
my $class = __PACKAGE__;
Are there any issues with simply doing using __PACKAGE__ when there's no special reason to try to detect what namespace the 'new' method is being called in?
Inheritance
# classA.pm
package ClassA;
sub new { $pkg = ref($_[0]) || $_[0] ; bless { foo => 42 }, $pkg }
# classB.pm
package ClassB;
use parent 'ClassA';
sub foo { ... }
# main.pl
use ClassA;
use ClassB;
$B = ClassB->new();
print $B->foo();
In this example, ClassB inherits methods from ClassA, including its constructor. But we still want to identify the object as belonging to ClassB, so the constructor in ClassA must respect the name of the reference passed to its constructor.
Easier and safer than
$B = bless { ClassA->new(), "ClassB" }; # or
$B = bless { ClassB->new(), "ClassA" };
or adding a pass-though constructor in ClassB.
package ClassB;
use parent 'ClassA';
sub new { bless { ClassA::new(#_), __PACAKGE__ } }
The class name is already the first argument to the constructor, so why not use that? You don't need to reach for anything and if you decide that the situation is more complex than you originally envisioned, you haven't artificially caused a speed bump. This code works with or without inheritance:
sub new {
my( $class, #args ) = #_;
...
bless {...}, $class;
}
Consider with anything that you program how much you'd have to change if the code situation changed. Maybe you add a couple of extra steps that you don't immediately need, but that keeps the code flexible for those times when you realize you actually needed those cases. In your case, you actually have to do extra work to ignore the invocant argument that Perl specifically provides to tell you which class is trying to mak a new object.
For example, you create your class, it works for you and does its job well. It works so well that you share it and someone else uses it and they are mostly happy with it for awhile until they need this one little modification. They should be able to subclass your module (so, no changes to it or for you) to extend or override a method. But, your code doesn't allow that because you blessed the object in a more restrictive way that didn't add any benefit.
That first bit of code in your question is using the first argument too, but it's not really a prescription for constructors. It's doing an extra thing by allowing an already existing object create a new one. The ref extracts the blessed package name from the object and uses that for the new object.
I don't particularly like that way of creating new objects and I think the interface will likely confuse people. What should happen when you call new on an existing object? Do you clone the existing one? If so, there are better names, such as clone (Ruby uses dup). Do you get a completely fresh object? If so, why do you go through an existing object to get one completely unrelated to it?
There was a time that many examples of OO Perl showed that same sort of constructor, and it was copy and pasted into many places. But we've learned a lot since then. Maybe you have a good answer why you'd allow that, but so far I haven't heard a compelling one.

Calling a Module Function By Reference

I am looking at building a dispatch table for calling a number of Perl modules that I wrote.
As an example, if I have a package called Hello.pm with a simple function hello() in it, I would like to get a code reference to this function.
The following does not work:
my $code_ref=\&Hello->hello();
$code_ref->();
But if the function hello is exported from the package, then the following works:
my code_ref=\&hello;
code_ref->();
Does anyone know the correct syntax for the first case? Or is this simply not possible?
In the end, I would like to populate a hash table with all my code references.
##### Thanks for All Answers
The correct invocation as pointed out by several answers is:
my $code_ref=\&Hello::hello;
$code_ref->();
I have some 10 modules in 10 different files that I would like to load in a dispatch table.
This makes it easier for me to have the configuration loaded as data, and separate from code.
This allows me to load additional modules in a testbench without modifying my code-simply modify the configuration file. Mark Dominus, author of Higher Order Perl, has some nice examples on this.
If you want to refer to the hello sub in the Hello module, then call it, use:
my $code_ref = \&Hello::hello;
$code_ref->();
If you want to call a method named "hello" in Hello, you can do it like this:
my $method = "hello";
Hello->$method();
\&NAME takes a reference to a sub. Hello->hello() is not a sub name. As an expression, it would be a method call.
To get a reference to a method, use can.
my $method_ref = Hello->can('hello');
That will search the inheritance tree if necessary. Now that you have a reference to the right method, you can call it:
Hello->$method_ref()
-or-
$method_ref->('Hello')
If you need a callback that can't call the method properly, you'll need to create a callback that does.
my $code_ref = sub { Hello->hello(#_) };
Here's what it looks like fully dynamic:
my $pkg = 'Hello'; # Also works with object!
my $method_name = 'hello';
my $method_ref = $pkg->can($method_name);
my $callback = sub { $pkg->$method_ref(#_) };
What you probably want is
my $code_ref = \&hello;
$code_ref->();

Perl: How to import subroutines from base class?

I have a base class, named Foo::Base, I need to inherit its methods, like 'new' and to import some subroutines names in a scope:
package Foo::Base;
sub new { ... }
sub import {
no strict 'refs';
my $caller = caller;
*{"${caller}::my_sub"} = sub { 1 };
}
1;
So, I need to use this base class in my second class, Foo::Child:
use base 'Foo::Base';
... and it works for inheritance, but it doesn't import 'my_sub' in a scope. I can add string
use Foo::Base;
for it and it helps, but I don't want to write something like this:
use base 'Foo::Base';
use Foo::Base;
This is looks kind of wierd... Is there any suggestions for this problem?
There's two reasons one might want to do what you're doing, both of them are bad.
First is you're trying to import methods from your parent class... for some reason. Maybe you misunderstand how OO works. You don't need to do that. Just call inherited methods as methods and unless those methods are doing something wacky it will work fine.
More likely is this a mixed-use module where some of it is methods and some of it is imported functions. And for that you can do...
use base 'Foo::Base';
use Foo::Base;
And you rightly observed that it looks kind of weird... because it is kind of weird. A class that also exports is mixing idioms, and that's going to result in weird usage patterns.
Best thing to do is to redesign the class to instead of exporting functions, either split the functions out into their own module, or make them class methods. If the functions really don't have much to do with the class, then its best to spin them off. If they do relate to the class, then make them class methods.
use base 'Foo::Base';
Foo::Base->some_function_that_used_to_be_exported;
This eliminates the interface mismatch, and as a bonus, subclasses can override class method behavior just like any other method.
package Bar;
use base 'Foo::Base';
# override
sub some_function_that_used_to_be_exported {
my($class, #args) = #_;
...do something extra maybe...
$class->SUPER::some_function_that_used_to_be_exported(#args);
...and maybe something else...
}
If you don't have control over the base class, you can still make the interface sane by writing a subclass which turns the exported functions into methods.
package SaneFoo;
use base 'Foo::Base';
# For each function exported by Foo::Base, create a wrapper class
# method which throws away the first argument (the class name) and
# calls the function.
for my $name (#Foo::Base::EXPORT, #Foo::Base::EXPORT_OK) {
my $function = Foo::Base->can($name);
*{$name} = sub {
my $class = shift;
return $function->(#_);
};
}
When you write use base, you're using the facilities of the base module. And you're passing it the parameter of of the module which you want to be your base class.
In an OO IS-A relationship, no import needed. You call the methods with the OO-pattern: $object_or_class->method_name( #args ). Sometimes that means that you don't care who the invocant is, like so:
sub inherited_util {
my ( undef, #args ) = #_;
...
}
or
sub inherited2 {
shift;
...
}
However, if you want to use utilities defined in the base module and inherit from the class behavior defined in that module, then that's exactly what the two use statements indicate.
Still, if you have two different types of behavior you want to use in modules, it's probably better to split the utility type things off into their own module, and use it from both modules. Either way, explicit behavior is often better than implicit.
However, I have used this pattern before:
sub import {
shift;
my ( $inherit_flag ) = #_;
my $inherit
= lc( $inherit_flag ) ne 'inherit' ? 0
: shift() && !!shift() ? 1
: 0
;
if ( $inherit ) {
no strict 'refs';
push #{caller().'::ISA'}, __PACKAGE__;
...
}
...
}
that way, I make one call with an explicit bundling of usages.
use UtilityParent inherit => 1, qw<normal args>;
To clarify a little more the question of "but why doesn't the import in Foo::Child work?", here's a program that will spell out what's actually happening:
use Foo::Child;
print my_sub(); # Really? Yes, really!
print Foo::Child::my_sub()," done\n";
and added this to the Foo::Base::import() routine:
print "Caller is $caller\n";
When you run this, you see this as the output:
Caller is main
1
Undefined subroutine &Foo::Child::my_sub called at foo_user.pl line 4.
We see Foo::Base reporting in, letting us know who the caller is: it's the main program! We see the '1', which proves that yes, main::my_sub now exists, and then the failure because the import went to the wrong namespace.
Why is this? Because the import process is all being handled by the main program. Foo::Base's import doesn't get called by anything in Foo::Child; it's getting called by the main program in the process of loading the modules. If you really, really want to force subs, as opposed to methods, to import into Foo::Child, you need to explicitly make it happen in Foo::Child itself. The 'use Foo::Base' will do it, as that makes the import execute with Foo::Child as the caller; if you insist on the import, but the double use squicks you out too much, you can call Foo::Base::import() right after the 'use base'. This is exactly what the double 'use' does anyway.
Nevertheless, I like Schwern's class methods better, and I recommend that alternative.

How do I inherit functions into an object and allow them to be used from given object?

I'm having trouble putting this question to better words, but how might I accomplish something like this:
FileSpecClone.pm
package FileSpecClone;
use File::Spec::Unix;
sub new() {
bless {};
}
CloneScript.pl
use FileSpecClone;
$obj = FileSpecClone->new();
# A FileSpec::Unix subroutine
$obj->catpath('a','b','c');
You must specify that FileSpecClone should inherit the methods of File::Spec::Unix by setting the package #ISA variable.
package FileSpecClone;
use File::Spec::Unix;
our #ISA = qw(File::Spec::Unix);
...
This is documented in perlobj.
If you have the parent module (a core module since v5.10), that will handle the details of setting #ISA at compile time. (HT: daxim)
use parent 'File::Spec::Unix';

How to access a hash in the main namespace from inside a module

I have my main Perl script which contains
my $System = {
Path =>
{
root => 'hello'
}
}
print $System->{'Path'}->{'root'}; # prints 'hello'
How can I access the $System->{'Path'}->{'root'} variable from an external module?
I know I can use the main:: namespace to retrieve global variables, such as $main::x, but the following doesn't work $main::System->{'Path'}->{'root'}.
I tried also different syntaxes but I'm not able to get it.
What am I doing wrong?
Variables declared with my only have lexical scope and are not visible in a package.
Declare it with our instead.
"Coping with Scoping":
http://perl.plover.com/FAQs/Namespaces.html