Wednesday, 14 March 2007

Objects in perl 5

There are many ways to do it. The old-school approach

blessed hash

sub new {
my $classname = shift;
my $rh = {}; # Reference to Hash, rh :)
bless $rh, $classname;
return $rh;

All variables can be created just by assigning something to blessed hash:

my $foo = my_class->new();
$foo->{bar} = 42;
print $foo->{bar};

Unfortunatelly there is lack of encapsulation - you have access to all methods and properties.

Get control of object properties - use fields

package my_class;
use fields qw(bar); # declare used object vars
sub new {
my $classname = shift;
return fields::new $classname;

# usage:
my my_class $foo = my_class->new();
$foo->{baz} = 42; # trying to use not declared field - error!
print $foo->{bar}; # works

We have control on object properties. Anyway, we still do not have private variables.

Private variables (scalar-bless)

package my_class;
my %bar; # All vars are declared as hashes
sub new {
my $classname = shift;
my $rs = \do{ my $scalar }; # reference to scalar
bless $rs, $classname;
return $rs;

sub set_bar {
my $this = shift;
$bar{$this} = shift;

sub get_bar {
my $this = shift;
return $bar{$this};

And now all variables are private!!!

Potential problem: it's not working with threads. To have a copy of such object instance in threads, you need to workaround this closure with get_all_data()/set_all_data() methods - and all object data need to be passed as additional parameters when creating new thread.

my $foo = my_class->new();
$foo->{bar} = 42; # sorry, no bonus! Use set/get method instead.
print $foo->{bar}; # This is private variable, not accessible outside class.
print $foo->get_bar(); # works!

Private, public, protected - objects like in perl6:

like in manual:

use Perl6::Classes;

class Composer {
submethod BUILD { print "Giving birth to a new composer\n" }
method compose { print "Writing some music...\n" }

class ClassicalComposer is Composer {
method compose {
print "Writing some muzak...\n";
method do_private is private { print "really private thing\n" }

class ModernComposer is Composer {
submethod BUILD($) { $.length = shift }
method compose() { print((map { int rand 10 } 1..$.length), "\n") }
has $.length;

my $beethoven = new ClassicalComposer;
my $barber = new ModernComposer 4;
my $mahler = ModernComposer->new(400);

$beethoven->compose; # Writing some muzak...
$barber->compose; # 7214
compose $mahler; # 8927586934796837469875

Pretty well, uhh? For me it was like "look, this is almost like in Java!" Just change is to extends.

Perl6::Classes works as a filter for code and do all this translation job. Well, we pay for it - it is 20x slower than hash/scalar blessed objects. If this latency doesn't matter - use it.

No comments: