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";
$_->do_private;
}
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
#$beethoven->do_private;
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: