juettemann juettemann - 6 months ago 20
Perl Question

Perl using a variable to reference a module messes up passing parameters

I have a problem when using a variable to reference a module, it seems to mess up the passing of the variables:

TOTO.pm



package TOTO;

use Data::Dumper;

sub print {
print Dumper(@_);
}


Perl program



package main;

TOTO::print('Hello World');
print ">>>>>>>>>>>\n";
my $package = 'TOTO';

$package->print('Hello World');


And the output is:

$VAR1 = 'Hello World';
>>>>>>>>>>>
$VAR1 = 'TOTO';
$VAR2 = 'Hello World';


Any advice on how to avoid having
TOTO
passed as the first variable?

Answer

Short: The observed behavior comes from use of -> on a package name.


The arrow operator is used with a reference or with an object, which is a reference to a data structure that has been bless-ed into its class. (Or with a class name, see below.) That object or the class name is quietly passed as the first argument so that the whole system would work. Note that the package in the question does not define a class (objects cannot be created with it).

From Arrow operator in perlop

"-> " is an infix dereference operator, just as it is in C and C++. If the right side is either a [...] , {...} , or a (...) subscript, then the left side must be either a hard or symbolic reference to an array, a hash, or a subroutine respectively. (Or technically speaking, a location capable of holding a hard reference, if it's an array or hash reference being used for assignment.) See perlreftut and perlref.

It continues, to statements of direct interest in this problem

Otherwise, the right side is a method name or a simple scalar variable containing either the method name or a subroutine reference, and the left side must be either an object (a blessed reference) or a class name (that is, a package name). See perlobj.

In uses related to classes the left-hand side may contain the class name, and class methods can then be invoked on it (or it can be just queried). Given that a class is a package then this is a package name.

The situation in the question falls within this so the package name is passed to the subroutine. However, according to the above quote is seems that the sub can only be a method, which isn't the case here. So it may be that this use of -> should really be disallowed. Either way, using it on a package which isn't a class strikes me as mistaken.

I am not really sure what the objective is with placing the package name in a variable and using the arrow operator on it. If you want to use a package, say as a library

File TOTO.pm

pacakge TOTO;

use Exporter;
our (@ISA, @EXPORT_OK);
@ISA = ('Exporter');
@EXPORT_OK = qw(prn);   # This can be asked for by user of package

use Data::Dumper;

sub prn {
       print Dumper(@_);
}

1;  # important for 'require' when this is used

I've changed the sub name to prn so that it's not a Perl library function. The main script

use warnings;
use strict;

use TOTO qw(prn);

prn("Hello World");

The fully qualified name TOTO::prn() can always be used. If you wanted to make this a class that would require a bit more in the package.

This package, TOTO, does not export anything by default, unless asked for. That's what @EXPORT_OK sets up and that's why we need to list functions to import into main:: when use TOTO. Start, for example, with perlmod