perloophashbless

In Perl, what's the underlying difference between a hash and a blessed reference?


I am new to Perl, and I would like to understand/know more about the OO parts. Say I have a "class" with only attributes; are there benefits/advantages for creating a package and blessing a hash over working on a hash directly?

for simplicity, lets consider the following example :

package Person;

sub new {
    my $class = shift;
    my $args = {Name => '', Age => 0, @_};
    
    my $self = { Name => $args->{Name},
                 Age => $args->{Age}, };
    
    bless $self, $class;
}


package main;

my $person1 = Person->new(Name => 'David', Age => 20);
my $person2 = {Name => 'David', Age => 20, Pet => 'Dog'};

print $person1->{Name} . "\n";
print $person2->{Name} . "\n";

What I would like to know is what is the difference between $person1 and $person2, beside the OO parts, beside the fact that 1 is a blessed hash and 2 is a hash reference?

Are there any benefits of working with an object, in this case, over working on a hash?

After reviewing the answers :

Thanks for all the help :)

Håkon Hægland comment has the closest answer for me, I was just wondering, consider I only have to hold, simple scalars, no special checks, no other functionality, are there benefits for a class over a simple hash (I understand that if I need extra functionality and inheritance a class will be the right tool)


Solution

  • If you are not going to use method calls, there is not so big difference. One thing you can do with $person1 is introspect the name of the class it was blessed into by calling ref $person1. You could also arrange for Person to inherit attributes from a base class.

    Another thing you could do with Person is to provide access validation to its data attributes. So instead of $person1->{Name} you would implement a method name() that returns $person1->{Name} and perhaps does some other useful things like logging, or checking if the name is defined and so on.

    For example:

    #! /usr/bin/env perl
    
    package LivingBeing;
    use strict;
    use warnings;
    sub new {
        die "LivingBeing: Wrong number of arguments to the constructor!" if @_ != 2;
        my ( $class, $type ) = @_;
    
        return bless {type => $type}, $class;
    }
    
    package Person;
    use strict;
    use warnings;
    use parent -norequire => qw(LivingBeing);
    sub new {
        my ($class, %args) = @_;
        my $self = $class->SUPER::new('human');
        $self->{age} = 0;  # Default value
        $self->{$_} = $args{$_} for keys %args;  # Maybe override default values..
        return $self;
    }
    
    sub name {
        my $self = shift;
        my $name = $self->{name};
        warn "Undefined name attribute" if !defined $name;
        return $name;
    }
    
    package main;
    use strict;
    use warnings;
    use feature qw(say);
    
    my $person1 = Person->new(pet => 'cat', age => 20);
    my $person2 = {name => 'David', age => 20, pet => 'dog'};
    
    say "person1 is a : ", ref $person1;
    say "person2 is a : ", ref $person2;
    
    say "The name of person1 is: ", $person1->name;
    say "The age of person1 is: ", $person1->{age};
    

    Output:

    person1 is a : Person
    person2 is a : HASH
    Undefined name attribute at ./p2.pl line 28.
    Use of uninitialized value in say at ./p2.pl line 43.
    The name of person1 is: 
    The age of person1 is: 20