I understand one uses the "bless" keyword in Perl inside a class's "new" method:
sub new {
my $self = bless { };
return $self;
}
But what exactly is "bless" doing to that hash reference ?
I understand one uses the "bless" keyword in Perl inside a class's "new" method:
sub new {
my $self = bless { };
return $self;
}
But what exactly is "bless" doing to that hash reference ?
In general, bless
associates an object with a class.
package MyClass;
my $object = { };
bless $object, "MyClass";
Now when you invoke a method on $object
, Perl know which package to search for the method.
If the second argument is omitted, as in your example, the current package/class is used.
For the sake of clarity, your example might be written as follows:
sub new {
my $class = shift;
my $self = { };
bless $self, $class;
}
bless
associates a reference with a package.
It doesn't matter what the reference is to, it can be to a hash (most common case), to an array (not so common), to a scalar (usually this indicates an inside-out object), to a regular expression, subroutine or TYPEGLOB (see the book Object Oriented Perl: A Comprehensive Guide to Concepts and Programming Techniques by Damian Conway for useful examples) or even a reference to a file or directory handle (least common case).
The effect bless
-ing has is that it allows you to apply special syntax to the blessed reference.
For example, if a blessed reference is stored in $obj
(associated by bless
with package "Class"), then $obj->foo(@args)
will call a subroutine foo
and pass as first argument the reference $obj
followed by the rest of the arguments (@args
). The subroutine should be defined in package "Class". If there is no subroutine foo
in package "Class", a list of other packages (taken form the array @ISA
in the package "Class") will be searched and the first subroutine foo
found will be called.
Short version: it's marking that hash as attached to the current package namespace (so that that package provides its class implementation).
This function tells the entity referenced by REF that it is now an object in the CLASSNAME package, or the current package if CLASSNAME is omitted. Use of the two-argument form of bless is recommended.
Example:
bless REF, CLASSNAME
bless REF
Return Value
This function returns the reference to an object blessed into CLASSNAME.
Example:
Following is the example code showing its basic usage, the object reference is created by blessing a reference to the package's class −
#!/usr/bin/perl
package Person;
sub new
{
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# Print all the values just for clarification.
print "First Name is $self->{_firstName}\n";
print "Last Name is $self->{_lastName}\n";
print "SSN is $self->{_ssn}\n";
bless $self, $class;
return $self;
}
I will try to provide an answer here since the ones here didn't quite click for me at the time I was initially writing this(warning, this answer is fairly poorly structured, feel free to skip over the parts that are not particularly useful to you).
Perl's bless function associates the specified reference with a package name string, and making the arrow operator of the blessed reference look for the method in the package associated with the reference, and if it does not find it, it continues looking using the @ISA
array if there is one(this is beyond the scope of this post).
Why would we need this?
Let's begin by expressing an example in JavaScript:
(() => {
//'use strict'; // uncomment to fix the bug mentioned below.
class Animal {
constructor(args) {
console.log(this);
this.name = args.name;
this.sound = args.sound;
}
}
/* This is left for historical reasons,
* modern JavaScript engines no longer allow you to
* call class constructors without using new.
*
* var animal = Animal({
* 'name': 'Jeff',
* 'sound': 'bark'
* });
* console.log(animal.name + ', ' + animal.sound); // seems good
* console.log(window.name); // my window's name is Jeff?
*/
// as of recently, Animal constructor cannot be called without using the new operator.
var animal = new Animal({
'name': 'Jeff',
'sound': 'bark'
});
console.log(animal.name + ', ' + animal.sound); // still fine.
console.log("window's name: " + window.name); // undefined
})();
Now let's look at the desugared version of the class construct:
(() => {
// 'use strict'; // uncomment to fix bug.
var Animal = function(args) {
this.name = args.name;
this.sound = args.sound;
return this; // implicit context hashmap
};
/**
* The bug left for historical reasons,
* should still work now in modern web developer consoles.
*
* var animal = Animal({
* 'name': 'Jeff',
* 'sound': 'Bark'
* });
* console.log(animal.name + ', ' + animal.sound); // seems good
* console.log("The window's name is: " + window.name); // my window's name is Jeff?
*/
// the new operator causes the "this" inside methods to refer to the animal
// rather than the global scope, so the bug mentioned above does not occur.
var animal = new Animal({
'name': 'Jeff',
'sound': 'bark'
});
console.log(animal.sound);
console.log(window.name); // the name has not been changed by the constructor.
})();
The Animal's constructor function takes an Object of properties and returns an Animal with those properties, or if you forgot to put the new keyword, it will return the whole global context(which is window
inside the browser developer console).
Perl has no "this" nor "new" nor "class", but it can still have a function that behaves similarly. We won't have a constructor nor a prototype, but we will be able to create new animals and modify their individual properties.
# immediatly invoked subroutine execution(IIFE).
(sub {
my $Animal = (sub {
return {
'name' => $_[0]{'name'},
'sound' => $_[0]{'sound'}
};
});
my $animal = $Animal->({
'name' => 'Jeff',
'sound' => 'bark'
});
print $animal->{sound};
})->();
Now, we have a problem: What if we want the animal to perform the sounds by themselves rather than having to print what their voice is directly. That is, we want a function performSound that prints the animal's own sound.
One way to do this is by giving each instance of an Animal its own performSound subroutine reference.
# self contained scope
(sub {
my $Animal = (sub {
$name = $_[0]{'name'};
$sound = $_[0]{'sound'};
return {
'name' => $name,
'sound' => $sound,
'performSound' => sub {
print $sound . "\n";
}
};
});
my $animal = $Animal->({
'name' => 'Jeff',
'sound' => 'bark'
});
$animal->{'performSound'}();
})->();
This is usually not what we want because performSound is put as a completely new subroutine reference for each animal that is constructed. Constructing 10000 animals would potentially allocate 10000 performSound subroutines. We want to have a single subroutine performSound that is used by all Animal instances that look up their own sound and print it.
(() => {
'use strict';
/* a function that creates an Animal constructor which can be used to create animals */
var Animal = (() => {
/* function is important, as fat arrow does not have "this" and will not be bound to Animal. */
var InnerAnimal = function(args) {
this.name = args.name;
this.sound = args.sound;
};
/* defined once and all animals use the same single function call */
InnerAnimal.prototype.performSound = function() {
console.log(this.name);
};
return InnerAnimal;
})();
var animal = new Animal({
'sound': 'bark',
'name': 'Jeff'
});
animal.performSound(); // Jeff
})();
Here is where the parallel to Perl kinda stops.
JavaScript's new operator is not optional, without it, "this" inside object methods contaminates the global scope:
(() => {
// uncommenting this prevents unintentional
// contamination of the global scope, and throws a TypeError instead.
// 'use strict';
var Person = function() {
this.name = "Sam";
};
// var wrong = Person(); // oops! we have overwritten window.name or global.main.
// console.log(window.name); // my window's name is Sam?
var correct = new Person; // person's name is actually stored in the person now.
})();
We want to have one function for each Animal that looks up that animal's own sound rather than hardcoding it at construction.
Blessing lets us use the package's subroutines rather than having to attach a subroutine ref to each object, it also makes ref
refer to the more meaningful package name(such as Animal
) as the name for the what the object is rather than a boring HASH
or whatever other referent you chose to bless:
package Animal;
sub new {
my $packageRef = $_[0];
my $name = $_[1]->{'name'};
my $sound = $_[1]->{'sound'};
my $this = {
'name' => $name,
'sound' => $sound
};
bless($this, $packageRef);
return $this;
}
# all animals use the same performSound to look up their sound.
sub performSound {
my $this = shift;
my $sound = $this->{'sound'};
print $sound . "\n";
}
package main;
my $animal = Animal->new({
'name' => 'Cat',
'sound' => 'meow'
});
print("The animal's ref is: " . ref($animal) . "\n");
$animal->performSound();
Summary/TL;DR:
Perl has no "this", "class", nor "new".
Blessing an object to a package gives that object a reference to the package.
Using the arrow operator to invoke a method of a blessed referent($blessedObject->method(...arguments)
) is often the same as calling Package::method($blessedObject, ...arguments)
, but if method is not found, it will continue looking using the @ISA
of the package which is beyond the scope of this post.
You can in fact create new classes at runtime, as long as you either violate strict 'refs' or use eval, here's a demonstration of how it can be done:
#!/usr/bin/perl
use warnings;
use strict;
print('Enter the name for the class(eg Greeter): $ ');
my $class_name = <>;
chomp $class_name;
print('Enter the name of the method(eg greet): $ ');
my $method_name = <>;
chomp $method_name;
no strict 'refs';
# The line below violates strict 'refs'.
*{$class_name . '::new'} = sub {
my $self = bless {}, $_[0];
return $self;
};
use strict 'refs';
no strict 'refs';
# The line below violates strict 'refs'
*{$class_name . '::' . $method_name} = sub {
print("Hello, World!\n");
};
use strict 'refs';
my $instance = ($class_name)->new();
$instance->$method_name();
Why the confusion?:
One reason why bless is confusing is because there are effectively three ways of calling a package
A::a()
, as a package subroutine.A->a()
, as a package subroutine, but that gets __PACKAGE__
passed as the first argument implicitly before the other arguments.$a->a()
with a blessed $a
into A
.The code below illustrates this:
# | Illustrates catching 3 distinct ways of calling a package's member.
package Test;
sub new {
return bless {}, __PACKAGE__;
}
sub runTest {
if (ref($_[0]) eq __PACKAGE__) {
# | $_[0] is the blessed reference.
# | Despite being called with "->", $_[1] is NOT "Test"(__PACKAGE__).
print("Test::runTest was called through a blessed reference call(\$instance->runTest().\n");
} elsif ($_[0] eq __PACKAGE__) {
# | $_[0] is "Test"(__PACKAGE__), but we can't determine for sure whether it was -> or ::.
print("Test::runTest was called through Test->runTest() or through Test::runTest() with 'Test' as the first argument.\n");
} else {
# | $_[0] is neither a blessed reference nor "Test"(__PACKAGE__), so it can't be an arrow call.
print "Test::runTest was called through Test::runTest()\n";
}
}
package main;
my $test = Test->new();
$test->runTest();
Test->runTest();
Test::runTest();
Test::runTest('Test'); # <- Same as "Test->runTest();"
Test::runTest($test); # <- Same as "$test->runTest();"
Another reason is that unlike JavaScript, Python, which can have multiple classes with different name but different definitions/methods/properties, Perl classes have unique(ref $obj
), as there can only be one package with a specific name at any given time, and @ISA takes a bit to get used to.
My final reason is that packages are less tangible than classes in other scripting languages where you can store a reference to the class itself inside a variable through the assignment operator, whereas in Perl not only can you not store references to the class(you can only refer to packages through their name strings), but trying to refer to a package through a name stored inside a variable (eg String[$method]) seems impossible without violating strict 'refs' or using eval.
Anyway hopefully somebody will find this post useful.
Note: this is a fairly old attempt at an answer, I have tried to clean up the amount of naive and embarassing/pointless/distracting statements, and adding more useful examples to help understand the concept, but it is still far from what I would like it to be(it is still fairly frustrating to re-read). I leave it as I still believe it may be of use to someone.
Please take it with a gain of salt, I apologize for any headache called by the poorly laid out structure of the answer.
my $o = bless {}, $anything;
will bless an object into the $anything
class. Similarly, {no strict 'refs'; *{$anything . '::somesub'} = sub {my $self = shift; return $self->{count}++};
will create a method named 'somesub' in the class named in $anything
. This is all possible at runtime. "Possible", however, doesn't make it a great practice to wield in every-day code. But it is useful in building object overlay systems such as Moose or Moo. –
Gorlovka unfortunately it makes it impossible(to my understanding) to create "new classes" at runtime
claim. I guess my concern ultimately boiled down to it being significantly less intuitive to manipulate/introspect the package system at runtime, but so far I have failed showing anything it inherently cannot do. Package system seem to support all the tools needed to add/remove/inspect/modify itself at runtime. –
Missive What specifically distinguishes a bless
-ed referent is that it gets additional internal content: the SV
for the reference (stored in the scalar) picks up an additional FLAGS
value (OBJECT
), and there is a STASH
which carries the package name (with a few other differences)
perl -MDevel::Peek -wE'
package Pack { sub func { return { a=>1 } } };
package Class { sub new { return bless { A=>10 } } };
$vp = Pack::func(); print Dump $vp; say"---";
$obj = Class->new; print Dump $obj'
Prints, with the same (and irrelevant for this) parts suppressed
SV = IV(0x12d5530) at 0x12d5540
REFCNT = 1
FLAGS = (ROK)
RV = 0x12a5a68
SV = PVHV(0x12ab980) at 0x12a5a68
REFCNT = 1
FLAGS = (SHAREKEYS)
...
SV = IV(0x12a5ce0) at 0x12a5cf0
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 1
---
SV = IV(0x12cb8b8) at 0x12cb8c8
REFCNT = 1
FLAGS = (PADMY,ROK)
RV = 0x12c26b0
SV = PVHV(0x12aba00) at 0x12c26b0
REFCNT = 1
FLAGS = (OBJECT,SHAREKEYS) <--
STASH = 0x12d5300 "Class" <--
...
SV = IV(0x12c26b8) at 0x12c26c8
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 10
With that it is known to the interpreter that
this is an object
what package it belongs to
and this informs its use.
For example, when dereferencing that variable ($obj->name
) a sub with that name is sought in the package (or hierarchy), the variable ("object") is passed as the first argument, etc.
I Following this thought to guide the development object-oriented Perl.
Bless associate any data structure reference with a class. Given how Perl creates the inheritance structure (in a kind of tree) it is easy to take advantage of the object model to create Objects for composition.
For this association we called object, to develop always have in mind that the internal state of the object and class behaviours are separated. And you can bless/allow any data reference to use any package/class behaviours. Since the package can understand "the emotional" state of the object.
bless($obj,'PackageName')
is a Perl builtin function to give $obj
access to all 'PackageName'
subs
For example:
use JSON;
#-- create json data
$data = {foo=>"bar"};
#-- lets print stringify using JSON
print JSON::encode_json($data);
# will print: {"foo":"bar"}
#-- let create object
$obj = { "xxx" => "yyy" };
#-- let try bless obj with JSON
bless($obj,'JSON');
#-- $obj still has "xxx"
print $obj->{xxx};
#will print yyy
#-- see above JSON has sub encode_json, now in $obj has all JSON subs
#-- include encode_json lest try:
print $obj->encode_json($data);
#-- error: Usage: JSON::XS::encode_json(scalar)
# why ?
# because $obj->encode_json is same as:
# JSON::encode_json($obj,$data)
# using $obj->mysub is set $obj as FIRST ARGUMENT of PackageName::mysub
# and this encode_json try to stringify $obj that already
# have all subs of package JSON
For example, if you can be confident that any Bug object is going to be a blessed hash, you can (finally!) fill in the missing code in the Bug::print_me method:
package Bug;
sub print_me
{
my ($self) = @_;
print "ID: $self->{id}\n";
print "$self->{descr}\n";
print "(Note: problem is fatal)\n" if $self->{type} eq "fatal";
}
Now, whenever the print_me method is called via a reference to any hash that's been blessed into the Bug class, the $self variable extracts the reference that was passed as the first argument and then the print statements access the various entries of the blessed hash.
© 2022 - 2024 — McMap. All rights reserved.