Search code examples
perlobjectreferenceperl-modulesubroutine

Manipulate Perl object by reference in subroutine


I have a Perl program and packages Worker and Log.

The Worker does almost all calculations, and I want to pass an object by reference to the Worker subroutine, as well as some other parameters (scalar and an array). I have seen examples like this and this.

They handle this by putting @_ in subs, then manipulating the object. I also found a way to manipulate them by using the index, like @{$_[i]}. Problem is, when I try the code like so, I get an error: Can't call method "write" on unblessed reference at ...

Code snippets below.

Main:

use strict;
use warnings;
use Log;
use Worker;

my $log = Log->new();
my $worker = Worker->new();
my $scalar = "SomeURLhere";
my @array = ('red','blue','white');

# I do some stuff with $log object
#...
# Now I want to pass data to the Worker
$worker->subFromWorker($scalar, \$log, \@array);

Worker:

use strict;
use warnings;
package Worker;

sub new {
    my $class = shift;
    my $self = {};
    bless $self, $class;
    return $self;
}

sub subFromWorker{
    my ($self) = shift;
    my $scalar = $_[0];
    #my ($log) = $_[1];
    my @array = @{$_[2]};

    foreach my $item (@array){
        print $item;
    }

    $_[1]->write("The items from url $scalar are printed.");

    #Same thing happens if I use $log here
}

In C#, this is handled in a different way - you can send a parameter to a method by value or by reference, and then do what you want in a specialized method (method is pre-written to handle parameters by reference or value). I thought that in Perl sending using \parameter will send the reference.


Solution

  • Objects are references. References are scalar values.

    If you want to pass arrays or hashes into a subroutine then you usually want to pass references to them - because Perl parameter passing works far better with scalar values.

    But $log is already a reference to your object. Therefore you don't need to take a reference to it. You end up passing a reference to a reference. So when you copy that parameter into $log inside your subroutine you have an extra, unnecessary, level of references.

    The fix is to just pass the $log scalar into the subroutine.

    $worker->subFromWorker($scalar, $log, \@array); # $log, not \$log
    

    Everything else will then work fine.