How to Bless Objects in a List Passed to a Subroutine?

125 Views Asked by At

In my Perl (v5.30.0) script, I have the world's simplest object:

#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;

package Thingee;
# Constructor with name new
sub new
{
        my $type = shift;
        my %params = @_;
        my $self = {};
        $self->{'somedata'} = $params{'somedata'};
        bless $self, $type;
}
sub printMe
{
        my ($self) = @_;
        printf "Data: \"%s\"\n", $self->{'somedata'};     # LINE 19
}

What could be simpler? Now, in the "main" body of my script, I create a list of Thingee objects. What I'm discovering is that the newly-created Thingees seem to be blessed upon creation... but if I pass the list to a subroutine, the same objects are seen as unblessed. Here's the code:

package main;

sub foo
{
        print "foo() ==========================================\n";
        my @ObjectArr = @_;
        print Dumper(@ObjectArr);
        foreach my $obj (@ObjectArr)
        {
                $obj->printMe();            # LINE 33
        }
}

# I make a list of objects:
my @ObjectArr = ();
push @ObjectArr, Thingee->new( 'somedata' => "My dog has fleas" );
push @ObjectArr, Thingee->new( 'somedata' => "My cat is fine" );

foreach my $obj (@ObjectArr)
{
        $obj->printMe();
}

foo(\@ObjectArr);

Output is:

Data: "My dog has fleas"
Data: "My cat is fine"
foo() ==========================================
$VAR1 = [
          bless( {
                   'somedata' => 'My dog has fleas'
                 }, 'Thingee' ),
          bless( {
                   'somedata' => 'My cat is fine'
                 }, 'Thingee' )
        ];
Can't call method "printMe" on unblessed reference at ./PassHash6.perl line 33.

Frustrating. In the "main" part of the code, I can iterate through the foreach loop, and the newly-created Thingee objects are accessible. But within the scope of subroutine foo(), the exact same foreach loop throws the Can't call method "printMe" on unblessed reference error. Harmuph!

My favorite explanation for why blessing is necessary comes from this SO post:

An unblessed reference is one where one variable is not a legal reference to an object[.]

Okay, that makes sense. But then how can all of the following be true:

  1. My Thingees are blessed within the scope of the "main" code
  2. My Thingees are not blessed within the scope of foo()
  3. Within foo(), my Thingees are nonetheless visible in the eyes of Data:Dumper()

Just for giggles, I modified the foreach() block within foo() to this:

foreach my $obj (@ObjectArr)
{
    bless $obj, "Thingee";     # New command here
    $obj->printMe();           # LINE 34
}

But now the script throws this error:

<EVERYTHING FROM BEFORE...>
Not a HASH reference at ./PassHash6.perl line 19.

Ugh. Line 19 is from the package Thingee section:

sub printMe
{
        my ($self) = @_;
        printf "Data: \"%s\"\n", $self->{'somedata'};     # LINE 19
}

Does anyone see what I'm doing wrong?

1

There are 1 best solutions below

3
On

You are passing a reference to an array to foo

foo(\@ObjectArr);

Inside of foo, you do

my @ObjectArr = @_;

@ObjectArr contains a exactly one element, the referenced passed to foo. This is not what you intended.


Option 1: foo accepts a reference to an array.

sub foo {
   my $objs = shift;
   $_->printMe() for @$objs;
}

foo( \@objs );

Option 2: foo accepts objects.

sub foo {
   $_->printMe() for @_;
}

foo( @objs );