Perl module class method vs ordinary subroutine - perl

So I was wondering if there is any difference in usage between a Perl class method and an ordinary subroutine from a standard module. Is there a time you would use one over the other? For this example, I'm assuming that no object methods are present in either module.
Quick little main class here:
#!/usr/local/bin/perl
use strict;
use warnings;
use Foo;
use Bar;
my $arg1 = "blah";
my ($str1, $str2);
$str1 = Foo::subroutine($arg1);
$str2 = Bar->subroutine($arg1);
exit(0);
Package Foo would hold my ordinary subroutine call
use strict;
use warnings;
package Foo;
sub subroutine {
my $arg = shift;
my $string = "Ordinary subroutine arg is $arg\n";
return $string;
}
1;
Package Bar would hold my class method call
use strict;
use warnings;
package Bar;
sub subroutine {
my $class = shift;
my $arg = shift;
my $string = "Class method arg is $arg\n";
return $string;
}
1;
Normally if I'm writing Perl code, I would just use the class method option (like with the Bar example), but I started pondering this question after reading some code from a former coworker that used the syntax like in the Foo example. Both seem to do the same thing inherently, but there seems to be more than meets the eye.

The decider is whether your Module is an object-oriented module or not.
If Module is simply a container for a collection of subroutines, then I would expect it to use Exporter and offer the opportunity to import a subset of its subroutines into the calling name space. An example is List::Util
On the other hand, if there is a constructor Module::new, and the intention is to use it in an OO manner, then you shouldn't mix simple subroutines in with methods (except perhaps for private subroutines that the module uses internally). An example is LWP::UserAgent
So I would expect the sources to be written like one or the other of these, and not a mixture in between. Of course there are always circumstances where a rule of thumb should be ignored, but nothing comes to mind in this case.
Foo.pm
use strict;
use warnings;
package Foo;
use Exporter 'import';
our #EXPORT_OK = qw/ subroutine /;
sub subroutine {
my ($arg) = #_;
"Ordinary subroutine arg is $arg\n";
}
1;
Bar.pm
use strict;
use warnings;
package Bar;
sub new {
my $class = shift;
bless {}, $class;
}
sub subroutine {
my $class = shift;
my ($arg) = #_;
"Class method arg is $arg\n";
}
1;
main.pl
#!/usr/local/bin/perl
use strict;
use warnings;
use Foo 'subroutine';
use Bar;
my $arg1 = "blah";
print subroutine($arg1);
print Bar->subroutine($arg1);
output
Ordinary subroutine arg is blah
Class method arg is blah

There's nothing inherently wrong with an ordinary subroutine. They do what they're designed to do very well.
Methods on the other hand, do all the same things and play nicely with any Class that inherits from yours.
So ask yourself:
Are you expecting/permitting/encouraging folks to write Classes that inherit from your module?
Is your module defining a more complex data structure that works well as an object?
or
Is your module a library of utilities that operate on fundamental data types?
There's plenty of room in this world for both, but if you find yourself, as you did in Bar, ignoring $class (or more commonly $self) throughout the module, then perhaps you've gone too far by designing them as methods. More importantly, anyone who tries to inherit from your marginally OO "Class" will get a rude surprise when your methods can't tell the difference between the two classes...

This is more a question of code paradigm.
There is absolutely nothing wrong with a non object oriented approach to your code. It works, and it works well.
However, object orientation provides a bunch of benefits that are worth considering - and if they're something you want, go an OO route.
Specifically - objects provide encapsulation. It makes it a lot easier for me to write a module and you to just use it. Look at say, LWP::UserAgent for an example:
require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
$ua->env_proxy;
$ua->agent('Mozilla/5.0');
my $response = $ua->get('http://search.cpan.org/');
if ($response->is_success) {
print $response->decoded_content; # or whatever
}
else {
die $response->status_line;
}
Now, all of the above you could do via inherited subroutines. But if you wanted to do multiple fetches of multiple pages, you'd either have to:
Build a sub that took all the parameters you needed - including returning somehow, a 'success/fail/result' - maybe in an array?
Otherwise have 'state' hidden in your external module.
OO is just a neater, more understandable method of doing that. (There are other benefits of doing OO, which I'm sure you could Google).

Related

"Can't locate object method "new" [...]" in Perl using the AI::Pathfinding::AStar CPAN module

This is the first "serious" thing I'm doing in Perl, so please pardon me if the question is somewhat silly.
I wanted to play around with the A* pathfinding algorithm. I found the AI::Pathfinding::AStar CPAN Module and am basically trying to get the given example to work.
First of all I separated the example into two files, because I couldn't figure out how to make the use My::Map::Package; work with everything in a single file. I came up with the following two files:
MyAstar.pm:
package MyAstar;
use warnings;
use strict;
use base "AI::Pathfinding::AStar";
my %NODES = get_all_nodes();
sub get_all_nodes {...}
sub getSurrounding {...}
main.pl:
#!/usr/bin/env perl
package main;
use lib '/home/foo/astar/';
use warnings;
use strict;
use MyAstar;
my $map = MyAstar->new or die "No map for you!";
my $path = $map->findPath(1, 5);
print join(', ', #$path), "\n";
When I execute main.pl I get the following error:
Can't locate object method "new" via package "MyAstar" at main.pl line 9.
I'm not sure what the problem is here. I would have expected, there to be a subroutine by the name new in the AI::Pathfinding::AStar package, but couldn't find it. Is the CPAN Module broken or am I doing something wrong?
You try to call a function (MyAstar->new, which conventionally is used as a constructor), but you don't define it. There is no default constructor in Perl (like in e.g., Java).
Add something like this to your MyAstar.pm:
sub new {
my $class = shift;
my $self = bless{}, $class;
# initialize $self here as needed, maybe using any passed arguments in #_
return $self;
}

imported perl variable imports with no value

SOLVED: As it turns out, my problem was rooted in the fact that I was not putting a $ in front of DEBUGVAR in the #EXPORT_OK assignment and the "use config_global qw(config DEBUGVAR);" line. Since it raises no error, I had no way to know this was the issue. So, the fix is to place the proper syntax in front of your variables at these points.
So I am trying to get the hang of writing and importing perl modules. I don't know why it was made so difficult to do this, but I am having a great deal of trouble with this seeimingly trivial task. Here is the contents of my module:
package global_config;
use strict;
require Exporter;
our #ISA = qw(Exporter);
our #EXPORT_OK = qw(DEBUGVAR);
our ($DEBUGVAR);
our $DEBUGVAR = "Hello, World!";
return 1;
Here are the contents of my perl script that imports the module:
use strict;
use config_global qw(config, DEBUGVAR);
our %config;
our $DEBUGVAR;
print "variable imported with value: ".$DEBUGVAR;
The output is "variable imported with value:", and nothing else. My variable appears to be losing it's value. What am I doing wrong?
EDIT: After fiddling around a bit, and turning warnings on, I have isolated the issue to being that $DEBUGVAR is never actually imported. When I use it via $config_global:DEBUGVAR, it works as expected. The issue now is that it is not importing into the namespace. What gives?
I see several issues:
You should not use a comma in the qw() syntax. The qw takes each whitespace separated phrase and puts it in an array element.
These two are the same:
my #bar = qw(foo bar barfu); #No commas!
my #bar = ("foo", "bar", "barfu"); #Commas Required
If you're exporting a variable, you need to put the sigil in front of it.
You have:
our #EXPORT_OK = qw(DEBUGVAR);
It should be:
our #EXPORT_OK = qw($DEBUGVAR);
You should use the newer Exporter syntax:
Here's the newer Exporter Syntax:
package global_config;
use strict;
use warnings;
use Exporter 'import'; #Not "require". No need for "#ISA"
our #EXPORT_OK = qw(DEBUGVAR);
our $DEBUGVAR = "Hello, World";
1; #Makes no real difference, but you shouldn't say "return 1". Just standard.
Finally, what are you doing exporting variables? That's just a bad practice.
Exporting anything is now questioned -- even functions. It pollutes the user's namespace. (At least you're using #EXPORT_OKAY). Take a look at File::Spec. It uses fully qualified package names for its subroutines by default.
The variable in question is accessible via the full package name $global_config::DEBUGVAR, so there's no real need to export it.
What if everybody did it? Yes, you last heard of this excuse in kindergarten, but it applies here. Imagine if several modules exported $DEBUGVAR.
There are several ways around your quandary, but the best is to use object oriented Perl to help set this variable, and even allow users to change it.
package MyPackage;
use strict;
use warnings;
use feature qw(say);
sub new {
my $class = shift;
my $debug = shift; #Optional Debug Value
my $self = {};
bless $self, $class;
if (not defined $debug) {
$debug = "Hello, world!";
$self->Debug($debug);
return $self;
}
sub Debug {
my $self = shift;
my $debug = shift;
if (defined $debug) {
$self->{DEBUG} = $debug;
}
return $debug;
}
1;
To use this module, I simply create a new object, and Debug will be set for me:
use strict;
use warnings;
use MyPackage #No exporting needed
#Create an object w/ Debug value;
my $obj = MyPackage->new; #Debug is the default.
say $obj->Debug; #Prints "Hello, world!"
# Change the value of Debug
$obj->Debug("Foo!");
say $obj->Debug; #Now prints "Foo!"
#Create a new object with a different default debug
$obj2 = MyPackage->new("Bar!");
say $obj2->Debug; #Print "Bar!";
This solves several issues:
It allows multiple values of debug because each object now has its own values
There is no worry about namespace pollution or accessing package variables. Again, all you need is contained in the object itself.
It's easier to debug issues since the complexity is hidden inside the objects themselves.
It's the new preferred method, so you might as well get use to the syntax and be able to read object oriented Perl code. You'll be seeing it more and more.
While exporting variables from a package isn't necessarily a recommended practice, to do so, you need to use the actual name of the variable you are exporting. In this case it is $DEBUGVAR and not DEBUGVAR which would be the name of a subroutine.
In the script using the config module, you do not need to declare the $DEBUGVAR variable as our, since imported variables are exempt from strict vars.
You have gotten the name mixed up, it looks like:
use config_global ...
package global_config;
Though one would think that would issue warnings. Unless you are not using warnings...?
ETA:
our #EXPORT_OK = qw($DEBUGVAR);
^
Also, you have two declarations on that variable. You really need to use warnings when debugging, otherwise, you'll never get anywhere.
Are you sure you want a comma here:
use config_global qw(config, DEBUGVAR);
Also, you aren't exporting config, so it might work better as:
use config_global qw(DEBUGVAR);
I'd also remove the last our $DEBUGVAR; since it might set it to undef (or at least put it before the "use" line) -- I am not sure about this though.

In Perl, how can I access a scalar defined in another package?

I seem to be stuck trying to access a scalar which is defined in another package, and have narrowed down an example to a simple test case where I can reproduce the issue.
What I wish to be able to do it access a reference to a list which is in defined within the package 'Example', using the our mechanism, however, Dumper is showing that the variable is always undefined within example.pl:
Example.pm looks like the following:
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
package Example;
use Data::Dumper;
my $exported_array = [ 'one', 'two', 'three' ];
print Dumper $exported_array;
1;
And the code which uses this package looks like this:
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
use Data::Dumper;
use lib '.';
use Example;
{ package Example;
use Data::Dumper;
our $exported_array;
print Dumper $exported_array;
}
exit 0;
Upon running this code, the first Dumper runs and things look normal, after this, the second Dumper, example.pl runs and the reference is then undefined:
$VAR1 = [
'one',
'two',
'three'
];
$VAR1 = undef;
A my declaration does not create a package level variable and does not enter anything onto the symbol table for any namespace.
To do what you look like you are trying to do, you will have to change the declaration in the first file to
our $exported_array = [ ... ];
You can then access it in another file as
$Example::exported_array
Even if $exported_array weren't lexically scoped in the Example package, Example's $exported_array and main's $exported_array are two different things. The easiest way to change the example you've given is to 1. change my to our in the Example declaration and explicitly qualify the variable name.
our $exported_array;
...
print Dumper $Example::exported_array;
Otherwise, you need to make Example an Exporter. (Or just write an Example::import routine--but I' not going to cover that.)
package Example;
our $exported_array = ...;
our #EXPORT_OK = qw<$exported_array>;
use parent qw<Exporter>;
And in the script:
use Example qw<$exported_array>;
However, as you can actually export arrays (not just refs), I would make that:
our #exported_array = (...);
our #EXPORT_OK = qw<#exported_array>;
...
use Example qw<#exported_array>;
...
print Dumper( \#exported_array );
When you use the my operator, you are lexically scoping the variable name to either the scope you're in or to the file.
If you want something to be visible as a qualified package array, you need to use our like you do in the driver code. I believe you also need to declare a few special exporter variables in the .pm file, but on the plus side you won't need to declare our $exported_array; in the driver file.
Using Exporter is fine for smaller projects, but if you have lots of code handling data that is internal to a module, things can get ... messy. Object-orientation is a lot friendlier for this type of thing.
Why not construct a method to fetch this data? In fact, why not just use Moose?
In your Example.pm, just load Moose - this gives you a constructor and destructor for free, as well as a subroutine to fetch values and turns on strict, etc by default. Array references have to be declared a little differently, due to how Class:MOP (The engine under the antlers of Moose) initializes attributes - you have to wrap it in a code reference (aka sub {}). You would also use Data::Dumper in the script which calls the package, instead of the package itself.
Example.pm
package Example;
use Moose;
has 'exported_array' => (is => 'rw', default => sub { [ 'one', 'two', 'three' ] });
1;
Then call this from a script:
example.pl
#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;
my $example = Example->new;
my $imported_array_ref = $example->exported_array;
my #imported_array = #{$imported_array_ref};
foreach my $element(#imported_array) { say $element; }
say Dumper(\#imported_array);
I made the dereferencing really explicit in the example.pl script above... it can be much more terse by dereferencing it directly into the array:
#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;
my $example = Example->new;
my #imported_array = #{$example->exported_array};
foreach my $element(#imported_array) { say $element; }
say Dumper(\#imported_array);
I think a lot more Perl programmers would embrace Moose if there were more simple examples that show how to get simple things done.
The Official Moose Manual is excellent, but it was really written for those who are already familiar with OOP.

package-variable-declaration question

What are the differences ( if any ) for me as the user of the package "Test::Test" between this two package-versions:
Test::Test;
require Exporter;
#ISA = qw(Exporter);
#EXPORT = qw(hello);
use strict; use warnings;
our $c = 3;
sub hello {
print "$_\n" for 0 .. $c;
}
.
Test::Test;
require Exporter;
#ISA = qw(Exporter);
#EXPORT = qw(hello);
$c = 3;
sub hello {
print "$_\n" for 0 .. $c;
}
It's a good practice to always enable strict and warnings. These pragmas help you to catch many simple errors and typos.
These two samples are equivalent. But the first one is preferred, because it explicitly declares the global variable $c using our and enables strictures and warnings.
FWIW, the proper way to write this module is like this:
package Test::Test;
use strict;
use warnings;
use Exporter 'import'; # gives you the import method directly
our #EXPORT = qw(hello);
my $c = 3;
sub hello {
print "$_\n" for 0 .. $c;
}
See perldoc Exporter for the best practices on writing modules with exports, for various scenarios.
I would also suggest changing the name of this package, as the Test:: namespace is already in use by core modules and CPAN distributions.
Variables in perl are by default global, regardless of whether they are declared in a module or not. The "my", "local" and "our" keywords scope the variable in different ways. In your example, "our $c" restricts the visibility of the variable to your package (unless you chose to export it, but that's another story).
So, for your latter example, any other piece of code that access and modify $c will impact your code too.
See http://perldoc.perl.org/functions/our.html for the official documentation on the "our" keyword.

How can I dynamically include Perl modules without using eval?

I need to dynamically include a Perl module, but if possible would like to stay away from eval due to work coding standards. This works:
$module = "My::module";
eval("use $module;");
But I need a way to do it without eval if possible. All google searches lead to the eval method, but none in any other way.
Is it possible to do it without eval?
Use require to load modules at runtime. It often a good idea to wrap this in a block (not string) eval in case the module can't be loaded.
eval {
require My::Module;
My::Module->import();
1;
} or do {
my $error = $#;
# Module load failed. You could recover, try loading
# an alternate module, die with $error...
# whatever's appropriate
};
The reason for the eval {...} or do {...} syntax and making a copy of $# is because $# is a global variable that can be set by many different things. You want to grab the value as atomically as possible to avoid a race condition where something else has set it to a different value.
If you don't know the name of the module until runtime you'll have to do the translation between module name (My::Module) and file name (My/Module.pm) manually:
my $module = 'My::Module';
eval {
(my $file = $module) =~ s|::|/|g;
require $file . '.pm';
$module->import();
1;
} or do {
my $error = $#;
# ...
};
How about using the core module Module::Load
With your example:
use Module::Load;
my $module = "My::module";
load $module;
"Module::Load - runtime require of both modules and files"
"load eliminates the need to know whether you are trying to require either a file or a module."
If it fails it will die with something of the like "Can't locate xxx in #INC (#INC contains: ...".
Well, there's always require as in
require 'My/Module.pm';
My::Module->import();
Note that you lose whatever effects you may have gotten from the import being called at compile time instead of runtime.
Edit: The tradeoffs between this and the eval way are: eval lets you use the normal module syntax and gives you a more explicit error if the module name is invalid (as opposed to merely not found). OTOH, the eval way is (potentially) more subject to arbitrary code injection.
No, it's not possible to without eval, as require() needs the bareword module name, as described at perldoc -f require. However, it's not an evil use of eval, as it doesn't allow injection of arbitrary code (assuming you have control over the contents of the file you are requireing, of course).
EDIT: Code amended below, but I'm leaving the first version up for completeness.
I use I used to use this little sugar module to do dynamic loads at runtime:
package MyApp::Util::RequireClass;
use strict;
use warnings;
use Exporter 'import'; # gives you Exporter's import() method directly
our #EXPORT_OK = qw(requireClass);
# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(#imports);
sub requireClass
{
my ($class) = #_;
eval "require $class" or do { die "Ack, can't load $class: $#" };
}
1;
PS. I'm staring at this definition (I wrote it quite a while ago) and I'm pondering adding this:
$class->export_to_level(1, undef, #imports);... it should work, but is not tested.
EDIT: version 2 now, much nicer without an eval (thanks ysth): :)
package MyApp::Util::RequireClass;
use strict;
use warnings;
use Exporter 'import'; # gives you Exporter's import() method directly
our #EXPORT_OK = qw(requireClass);
# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(#imports);
sub requireClass
{
my ($class) = #_;
(my $file = $class) =~ s|::|/|g;
$file .= '.pm';
require $file; # will die if there was an error
}
1;
Class::MOP on CPAN has a load_class method for this:
http://metacpan.org/pod/Class::MOP
i like doing things like..
require Win32::Console::ANSI if ( $^O eq "MSWin32" );