3

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?

Dada
  • 6,313
  • 7
  • 24
  • 43
Pete
  • 1,511
  • 2
  • 26
  • 49
  • 1
    Tip: `print( Dumper( @a ) );` is confusing. Use `print( Dumper( \@a ) );` (Same for hashes.) – ikegami Nov 23 '22 at 16:27
  • @ikegami Thanks Ikegami, you save me once again. You're like a Perl guardian angel. Thanks for the tip! In a tricky language like Perl, I need all the syntax tips I can get. – Pete Nov 23 '22 at 16:38

1 Answers1

4

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 );
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Excellent thank you! I didn't realize that passing the list as a ref to "main"'s array was passing one indivisible object. THAT makes a lot of sense. I'll modify `foo()` to understand the ref to an array, thank you! – Pete Nov 23 '22 at 16:40
  • 1
    @Pete, You keep calling arrays lists. Don't do that. List is used refer to many things, and adding arrays to that list makes things worse. – ikegami Nov 23 '22 at 16:48
  • 1
    You're not passing "a list as a reference". You are (creating and) passing a reference (to an array). Since you pass a reference, you receive a reference. – ikegami Nov 23 '22 at 16:49