Perl Part I · Module 12 · Modules and Packages
bless: How a Perl Object Works
Perl's object system has a reputation for being strange, and the reputation is deserved mainly because it is so much smaller than people expect. There are no class declarations, no field lists, no privacy keywords and no special object type. There is a function that writes a package name onto a reference, and a calling convention that passes the thing on the left of an arrow as the first argument to a subroutine. Everything else that looks like object orientation in Perl — constructors, accessors, inheritance, the whole of Moo and Moose — is built out of those two pieces using the ordinary language you already know. This chapter measures both, including the clearest demonstration available: calling a method with the arrow and then calling the identical subroutine by its full name with the object passed as an argument, and getting the same answer. Once that lands, reading object-oriented Perl written by somebody else becomes a matter of following subroutine calls, which is the next and final chapter of the module.
Advanced13 min readPerlPart IModules
Part I · Module 12 · Chapter 12.12 · bless: How a Perl Object Works
1. What an Object Is
An object is a reference with a label
use strict;
use warnings;
use Scalar::Util qw(reftype);
my $plain = { pin => "u_alu/A", slack => -0.12 };
my $blessed = { pin => "u_alu/A", slack => -0.12 };
bless $blessed, "VLSI::Path";
printf "ref(plain) : %s\n", ref($plain);
printf "ref(blessed) : %s\n", ref($blessed);
printf "reftype(both) : %s and %s\n", reftype($plain), reftype($blessed);
printf "keys match : %s\n",
(join(",", sort keys %$plain) eq join(",", sort keys %$blessed) ? "yes" : "no");
printf "blessed->{slack} : %s\n", $blessed->{slack};
print "\nbless changed what ref() SAYS; underneath both are still plain hashes\n";ref(plain) : HASH
ref(blessed) : VLSI::Path
reftype(both) : HASH and HASH
keys match : yes
blessed->{slack} : -0.12
bless changed what ref() SAYS; underneath both are still plain hashesTwo identical hash references, one of them blessed. ref reports HASH for the first and VLSI::Path for the second — and reftype from Scalar::Util reports HASH for both.
That is the measurement. bless wrote a label onto the reference. It did not copy the data, change the data, restrict the data, or convert the reference into a different kind of thing. The keys are identical, and $blessed->{slack} still works exactly as it did in Module 7, because the blessed reference is still a hash reference.
A useful way to hold this: bless is closer to a sticker than to a constructor. The sticker says which package to consult, and Chapter 7.14 already measured its visible effect — ref returns Regexp for a qr//, and that is the same mechanism, since a compiled pattern is a blessed reference.
2. The Arrow Is a Calling Convention
use strict;
use warnings;
package VLSI::Path {
sub new {
my ($class, %args) = @_;
my $self = { pin => $args{pin}, slack => $args{slack} };
return bless $self, $class;
}
sub pin { my ($self) = @_; return $self->{pin} }
sub slack { my ($self) = @_; return $self->{slack} }
sub is_violation { my ($self) = @_; return $self->{slack} < 0 ? 1 : 0 }
sub whoami { my ($self) = @_; return ref($self) }
}
my $p = VLSI::Path->new(pin => "u_alu/A", slack => -0.12);
printf "pin : %s\n", $p->pin;
printf "slack : %s\n", $p->slack;
printf "is_violation : %d\n", $p->is_violation;
printf "ref : %s\n", ref($p);
printf "whoami : %s\n", $p->whoami;
# The arrow call is sugar for passing the invocant as the first argument
printf "same via full name : %s\n", VLSI::Path::pin($p);
print "\n\$obj->method(...) IS Package::method(\$obj, ...)\n";pin : u_alu/A
slack : -0.12
is_violation : 1
ref : VLSI::Path
whoami : VLSI::Path
same via full name : u_alu/A
$obj->method(...) IS Package::method($obj, ...)The last two lines before the summary are the point of the chapter. $p->pin and VLSI::Path::pin($p) returned the same string, because they are the same call.
$thing->method(@args) does two things: it works out a package name, and it calls Package::method($thing, @args). If $thing is a blessed reference, the package is the class the reference was blessed into. If $thing is a bare name like VLSI::Path, the package is that name — which is why VLSI::Path->new(...) passes the string "VLSI::Path" as the first argument, and why new receives it as $class.
Everything in the module above follows from that:
new is not special. It is an ordinary subroutine that happens to be called on the class, build a hash reference, and bless it. The name new is pure convention; create or from_line would work identically. Nothing in Perl knows what a constructor is.
bless $self, $class rather than bless $self, "VLSI::Path" is the habit to adopt. Using the passed-in class name means a subclass inheriting this constructor blesses into the subclass, which is the behaviour inheritance needs. Hard-coding the name is the single most common bug in a hand-written Perl constructor.
The accessors are three lines each and there is nothing clever in them. my ($self) = @_; unpacks the invocant — Module 10's argument handling, unchanged — and then it is just a hash lookup.
There is no privacy. $p->{slack} works from anywhere, as section one showed. An object's fields are as public as a hash's keys, which is less private than Chapter 12.11's closure. Perl's convention is a leading underscore on a field name to mean "internal", enforced by nothing but manners.
3. Asking What an Object Can Do
use strict;
use warnings;
package VLSI::Path {
sub new { my ($c,%a)=@_; return bless {%a}, $c }
sub describe { my ($s)=@_; return "path " . $s->{pin} }
}
my $p = VLSI::Path->new(pin => "u_alu/A");
printf "describe : %s\n", $p->describe;
printf "can('describe') : %s\n", ($p->can('describe') ? "yes" : "no");
printf "can('nonexistent'): %s\n", ($p->can('nonexistent') ? "yes" : "no");
printf "isa('VLSI::Path') : %s\n", ($p->isa('VLSI::Path') ? "yes" : "no");
my $ok = eval { $p->nonexistent; 1 };
my ($first) = split /\n/, ($@ // "");
$first =~ s/ at .* line \d+.*$//;
printf "calling a missing method : %s\n", $first;describe : path u_alu/A
can('describe') : yes
can('nonexistent'): no
isa('VLSI::Path') : yes
calling a missing method : Can't locate object method "nonexistent" via package "VLSI::Path"can answers whether a method exists and returns a code reference if it does, which makes it the way to check for an optional method before calling it. isa answers whether the object belongs to a class or inherits from it.
The error for a missing method is worth reading carefully:
Can't locate object method "nonexistent" via package "VLSI::Path"
It names the package Perl searched, which is the information you need. The two failures that produce a confusingly similar message are both worth recognising. If the package name in the error is not the one you expected, the object was blessed into something else — possibly by a hard-coded bless in a parent class. And if the message says via package "VLSI::Path" (perhaps you forgot to load "VLSI::Path"?), the class has no methods at all because its file was never loaded, which is Chapter 12.5's path-mismatch failure arriving in object form.
4. Any Reference Can Be Blessed
Hash references are the usual choice and not the only one.
use strict;
use warnings;
# An object does not have to be a hash. bless marks any reference.
my $array = bless [1, 2, 3], "Holder::Array";
my $scalar = do { my $v = 42; bless \$v, "Holder::Scalar" };
my $code = bless sub { "called" }, "Holder::Code";
printf "ref(array ) : %-14s contents : %s\n", ref($array), join(",", @$array);
printf "ref(scalar) : %-14s contents : %s\n", ref($scalar), $$scalar;
printf "ref(code ) : %-14s contents : %s\n", ref($code), $code->();
# reftype tells you what it REALLY is underneath
use Scalar::Util qw(reftype blessed);
printf "\nreftype(array) : %s blessed(array) : %s\n", reftype($array), blessed($array);
printf "reftype({}) : %s blessed({}) : %s\n", reftype({}), (blessed({}) // "undef");ref(array ) : Holder::Array contents : 1,2,3
ref(scalar) : Holder::Scalar contents : 42
ref(code ) : Holder::Code contents : called
reftype(array) : ARRAY blessed(array) : Holder::Array
reftype({}) : HASH blessed({}) : undefAn array reference, a scalar reference and a code reference, all blessed, all still usable as what they are — @$array works, $$scalar works, $code->() works.
Hash references dominate because a hash gives you named fields, which is what most objects want. The others appear in real code: a blessed scalar reference is a common way to make an object whose fields genuinely cannot be reached, and a blessed code reference is how some callback wrappers are built.
The last two lines are the pair of tools to remember from Scalar::Util, because ref conflates two questions:
reftype($x)— what kind of reference is it really? AlwaysHASH,ARRAY,CODEand so on.blessed($x)— what class does it claim, orundefif it is not blessed.
blessed($x) is the correct test for "is this an object". Testing ref($x) eq 'HASH' to mean "a plain hash reference" is right; testing ref($x) against a class name works but breaks under inheritance, where isa is the proper question.
5. What This Buys, and What It Costs
Returning to Chapter 12.11's closing question. Module-level state gives one copy for the process; an object gives one copy per object, which is the whole reason to reach for it.
So the decision rule is concrete. If the state describes a thing there can be two of, use an object. Two reports, two paths, two connections, two parsers with different settings. Chapter 12.11's cache is correctly module-level because there is only ever one cache; a VLSI::Path is correctly an object because a design has thousands.
The costs are real and worth stating, since Perl's system is thin enough that you pay them yourself:
- No field declarations, so a typo in
$self->{sclak}creates a new key and reads asundef. This is Chapter 12.7's fully-qualified-typo problem in a new place, and it is the main argument for Moo or Moose, which do declare fields. - No privacy, so every field is public whether you meant it or not.
- Accessors are yours to write, which is tedious enough that it is the second argument for Moo or Moose.
- Inheritance is
@ISAand manual care, including thebless $self, $classhabit above.
For a script, a plain blessed hash with three accessors is proportionate. For a library other people will build on, a declarative system earns its dependency — and Chapter 12.13 is about reading both when you meet them.
6. What To Remember
blesswrites a package name onto an existing reference. Measured:refchanges,reftypedoes not, the keys are identical, and the blessed reference still works as a hash reference.$obj->method(@args)isPackage::method($obj, @args). Measured by calling both ways and getting the same result. That is the entire object system.Class->new(...)passes the class name as the first argument, which is whynewreceives$class.newis not special — it is a convention, and nothing in Perl knows what a constructor is.- Always
bless $self, $class, never a hard-coded name, or subclasses break. - There is no privacy.
$obj->{field}works from anywhere; a leading underscore is manners, not enforcement. canreturns a code reference or false;isaanswers class membership including inheritance.- The missing-method error names the package it searched — if that is not the package you expected, the
blessis wrong; if it suggests you forgot to load it, the file never loaded. - Any reference can be blessed, and
Scalar::Utilsplits the question:reftypefor what it is,blessedfor what class it claims. - Use an object when the state describes a thing there can be two of. Module-level state is one copy per process.
- The costs are no field declarations, no privacy, and hand-written accessors — which is what Moo and Moose exist to fix.
Chapter 12.13 closes the module with the skill this one makes possible: taking an object-oriented Perl script somebody else wrote, finding its constructor, following its inheritance, recognising a Moo or Moose attribute, and working out where a method is actually defined.
Where this fits
Part of the Perl curriculum.
