Question

I have a perl mason file and one of the lines looks like this:

$result = PI::Membership::Service->cancel(name => $name)

What exactly does that mean? Is it calling another module? Is it object oriented perl code?

Thanks

Was it helpful?

Solution

It is calling (invoking) the subroutine PI::Membership::Service::cancel with three arguments.

  1. "PI::Membership::Service"
  2. "name"
  3. $name

Given normal naming conventions, this is calling a subroutine called cancel in the package PI::Membership::Service, defined in a file named PI/Membership/Service.pm somewhere along your @INC path (there are many abnormal naming conventions, however, so there is no guarantee you will find such a file). And if the PI::Membership::Service package (class) inherits from one or more other packages, the cancel subroutine might actually be defined in one of those packages.

More details in perlobj.

OTHER TIPS

Unless $result is a Pi::Membership::Service object, it's not really an object oriented call because it's neither creating or manipulating an object. An object oriented call would look like this:

my $obj = Foo::Bar->new;   #Creating an object of class `Foo::Bar`
$obj->Baz                  #Calling method "Baz" on object "$obj";

It looks like this is an object style call to access a subroutine that's in another package and has not been exported.

To understand what's really going on, you must know about namespaces. Perl uses namespaces. Most of the time you might not be aware of it because you are using the default namespace of main. Namespaces are needed because you could end up (especially in pre-4.x versions of Perl) function and variable name collisions. Here's a program I have written in the old Perl 3.x style:

require "fribulate.pl";
$value = 4.5;
$new_value = fribulate($value);
print "Fribulated Value = $new_value  Original value = $value\n";

And here's my fribulate.pl program:

sub fribulate {
    my $param = shift;
    $value = $param * 2;
    return $value * 6;
}
1;

When I run my program, I get:

 Fribulated Value = 54. Original Value = 9

Wait? Wasn't it originally 4.5? The fribulate.pl program affected my $value because it is also using a variable called $value. To get around this, Perl created the package command that creates a new namespace:

package Fribulate;
sub fribulate {
    my $param = shift;
    $value = $param * 2;
    return $value * 3.1416;
}
1;

Now, the fribulate.pl program is not in namespace main, but in namespace Fribulate. Thus, the $value variable used in fribulate.pl isn't the same as my $value variable.

However, I can access a variable in another namespace if I prepend the namespace on it:

require "fribulate.pl";
$value = 4.5;
$new_value = fribulate($value);
print "Fribulated Value = $new_value  Original value = $value\n";

# Printing the value of $value from frimbulate.pl:
print "And in fribulate.pl, it's using $Fribulate::value\n";

You would have seen this if you used File:Find. To access the full name of a file, you use $File::Find::name. To access the file's directory, you use $File::Find::dir. The namespace File::Find is being prepended to the $dir and $name variables in File::Find.

The problem with namespaces is that everything is now in the new namespace, including my frimbulate function in frimbulate.pl. Thus, my original program also has to prepend the namespace in front of the function in order to work:

require "fribulate.pl";
$value = 4.5;
$new_value = Frimbulate::fribulate($value);
print "Fribulated Value = $new_value  Original value = $value\n";

To get around this issue, you did a little fancy footwork in the frimbulate.pl program:

Package Frimbulate;

require Exporter;
@EXPORT = qw(frimbulate);

sub fribulate {
    my $param = shift;
    $value = $param * 2;
    return $value * 3.1416;
}
1;

The Exporter package sprinkles magic pixie dust1 on the functions in @EXPORT and makes them available into the main namespace -- the default namespace where all of your stuff resides. Thus, modules like File::Copy and File::Basename use Exporter to allow you to access their respective copy and basename subroutines without prepending the package name in front of them.

This is now considered bad style because you could end up overwriting other subroutines with the same name without any warning. In the new style of writing modules, you no longer automatically export all of your functions in the @EXPORT array. You'll notice this in File::Path which doesn't automatically export its functions into the main namespace without our explicitly requesting it. Instead, you put them in @EXPORT_OK which requires users to ask them to be pushed into the namespace:

Frimbulate Package

Package Frimbulate;

require Exporter;
@EXPORT_OK = qw(frimbulate); #You have to request the frimbulate subroutine

sub fribulate {
    my $param = shift;
    $value = $param * 2;
    return $value * 3.1416;
}
1;

My Program:

# Now I have to ask that the frimbulate subroutine be import into my main namespace
require "fribulate.pl" qw(frimbulate);
$value = 4.5;
$new_value = fribulate($value);
print "Fribulated Value = $new_value  Original value = $value\n";

This should now give you enough background to read the Perl Module documentation and quite possibly understand what's going on. The Perlmod documentation covers namespaces, the symbol table, and even a bit about variable scope. It's contains a lot of information, and can be a bit intimidating without basic information.


1 No pixies were harmed in use of the Exporter module. If you look at Exporter.pm which you can find with the perldoc -l Exporter command, you'll see that it's directly manipulating the symbol table.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top