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.