This morning, I came across this discussion on Reddit. Following the lead of dams and zakame, I had been playing with p5-mop, so I decided to compare.
First, here is singe's original example using Object::Tiny
#!/usr/bin/env perl
use v5.18;
use warnings;
package myBaseClass {
use Object::Tiny qw(myID myName);
sub doMsg {
my($self, $m) = @_;
say $m;
}
}
package myDerivedClass {
use parent -norequire, 'myBaseClass';
sub hello { say __LINE__.' Hello from '.__PACKAGE__; }
}
my $v= myDerivedClass->new(myID => time , myName => 'DC');
$v->hello;
$v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
How does that compare to not using a framework at all?
#!/usr/bin/env perl
use v5.18;
use warnings;
package myBaseClass {
sub new {
my($class, %args) = @_;
bless {%args}, $class;
}
sub myID {
my $self = shift;
$self->{myID} = shift if @_;
$self->{myID};
}
sub myName {
my $self = shift;
$self->{myName} = shift if @_;
$self->{myName};
}
sub doMsg {
my($self, $m) = @_;
say $m;
}
}
package myDerivedClass {
use parent -norequire, 'myBaseClass';
sub hello { say __LINE__.' Hello from '.__PACKAGE__; }
}
my $v = myDerivedClass->new(myID => time , myName => 'DC');
$v->hello;
$v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
In the base class, we have to write our own constructor (new) and our own accessors (myID and myName). The derived class doesn't change at all.
Now, what if we had a MOP built in to Perl? If we have a recent version of Perl installed with a recent version of cpanm, we can try that out lickety split with
$ cpanm --dev twigils
$ cpanm git://github.com/stevan/p5-mop-redux.git
This installs the development version of twigils and the github version of p5-mop-redux. These are still being developed, of course, but they are working. What does it look like when we use them?
#!/usr/bin/env perl
use v5.18;
use warnings;
use mop;
class myBaseClass {
has $!myID is ro = 0;
has $!myName is ro = '';
method doMsg ($m) { say $m }
}
class myDerivedClass extends myBaseClass {
method hello { say __LINE__.' Hello from myDerivedClass' }
}
my $v = myDerivedClass->new(myID => time , myName => 'DC');
$v->hello;
$v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
Nice! We have a class keyword for the classes, a method keyword for the methods, and a has keyword for the attributes. And methods have real signatures. I could get used to that very quickly, I think!
What does it look like using Moose? Let's ignore the namespace and immutability issues.
#!/usr/bin/env perl
use v5.18;
use warnings;
package myBaseClass {
use Moose;
has 'myID' => (is => 'ro');
has 'myName' => (is => 'ro');
sub doMsg {
my($self, $m) = @_;
say $m;
}
}
package myDerivedClass {
use Moose;
extends 'myBaseClass';
sub hello { say __LINE__.' Hello from '.__PACKAGE__; }
}
my $v = myDerivedClass->new(myID => time , myName => 'DC');
$v->hello;
$v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
Here we still use package and sub, but we get has and extends.
It looks the same with Moo.
#!/usr/bin/env perl
use v5.18;
use warnings;
package myBaseClass {
use Moo;
has 'myID' => (is => 'ro');
has 'myName' => (is => 'ro');
sub doMsg {
my($self, $m) = @_;
say $m;
}
}
package myDerivedClass {
use Moo;
extends 'myBaseClass';
sub hello { say __LINE__.' Hello from '.__PACKAGE__; }
}
my $v = myDerivedClass->new(myID => time , myName => 'DC');
$v->hello;
$v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
How about MooseX::Declare?
#!/usr/bin/env perl
use v5.18;
use warnings;
use MooseX::Declare;
class myBaseClass {
has 'myID' => (is => 'ro');
has 'myName' => (is => 'ro');
method doMsg (Str $m) { say $m }
}
class myDerivedClass extends myBaseClass {
method hello { say __LINE__.' Hello from '.__PACKAGE__ }
}
my $v = myDerivedClass->new(myID => time , myName => 'DC');
$v->hello;
$v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
This restores the class and method keywords and the method signatures. Unfortunately, I was disappointed to learn at YAPC::NA this year that MooseX::Declare is frowned upon. Apparently, the magic of Devel::Declare is too deep for modern software engineering. Bummer.
But now there's Moops, which aims to do the same thing without using Devel::Declare.
#!/usr/bin/env perl
use v5.18;
use warnings;
use Moops;
class myBaseClass {
has 'myID' => (is => 'ro');
has 'myName' => (is => 'ro');
method doMsg (Str $m) { say $m }
}
class myDerivedClass extends myBaseClass {
method hello { say __LINE__.' Hello from '.__PACKAGE__ }
}
my $v = myDerivedClass->new(myID => time , myName => 'DC');
$v->hello;
$v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
Hooray for Moops!
Now this is just one tiny example with only simple inheritance, but I think it's instructive to see several ways to do it in Perl. I've been playing with Go a lot lately, which doesn't even have inheritance; everything is done via composition. In Perl, we would do this with roles. I didn't even mention roles above, but I think I could do another whole post on Role::Tiny, Moose roles, Moo::Role, and mop roles.
Update (2013-09-25): Oops, I forgot Class::Tiny! This example is so small that it looks the same as Object::Tiny.
#!/usr/bin/env perl
use v5.18;
use warnings;
package myBaseClass {
use Class::Tiny qw(myID myName);
sub doMsg {
my($self, $m) = @_;
say $m;
}
}
package myDerivedClass {
use parent -norequire, 'myBaseClass';
sub hello { say __LINE__.' Hello from '.__PACKAGE__; }
}
my $v= myDerivedClass->new(myID => time , myName => 'DC');
$v->hello;
$v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
By the way, all of these examples do the same thing
$ ./useClassTiny.pl
18 Hello from myDerivedClass
DC Very nice! How much RAM is Eclipse using?
except for that changing line number.
Recent Comments