Last week, I talked about some of the ways we have to do objects in Perl. I also mentioned that in Go, we don't have classes or inheritance; everything is done with composition. What does that look like?
package main import ( "fmt" "runtime" "time" ) type MyBase struct { MyID time.Time MyName string } func (MyBase) DoMsg (m string) { fmt.Println(m) } type MyDerived struct { MyBase } func (MyDerived) SayHello () { _, _, line, _ := runtime.Caller(0) fmt.Println(line, "Hello from MyDerived") } func main() { v := MyDerived{MyBase:MyBase{MyID: time.Now(), MyName: "DC"}} v.SayHello() v.DoMsg(v.MyName + " Very nice! How much RAM is Eclipse using?") }
We don't have classes, but we can make our own types and attach methods to them. Here MyBase has a couple of attributes and it knows how to DoMsg, while MyDerived knows how to SayHello and delegates everything else to MyBase. So when we create v, it knows how to both SayHello and DoMsg. We can compile and run the above with
$ go run foo.go 23 Hello from MyDerived DC Very nice! How much RAM is Eclipse using?
Delegates? If you've seen Ovid talk about "Roles versus Inheritance", perhaps you think delegation is a failed solution to the inheritance problem. I'm still a beginner with Go, but so far I think it works pretty well.
In Perl, we do composition with roles. I first encountered this with Moose.
#!/usr/bin/env perl use v5.18; use warnings; package myRole { use Moose::Role; has 'myID' => (is => 'ro'); has 'myName' => (is => 'ro'); sub doMsg { my($self, $m) = @_; say $m; } } package myClass { use Moose; with 'myRole'; sub hello { say __LINE__.' Hello from '.__PACKAGE__; } } my $v = myClass->new(myID => time , myName => 'DC'); $v->hello; $v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
This example is so small, that it looks almost exactly like it did with inheritance. Package myRole looks just like myBaseClass did, except we use Moose::Role instead of Moose. Then myClass looks just like myDerivedClass did, except we say with to consume the role, instead of extends to inherit the class.
The same is true of Moo::Role and Moo.
#!/usr/bin/env perl use v5.18; use warnings; package myRole { use Moo::Role; has 'myID' => (is => 'ro'); has 'myName' => (is => 'ro'); sub doMsg { my($self, $m) = @_; say $m; } } package myClass { use Moo; with 'myRole'; sub hello { say __LINE__.' Hello from '.__PACKAGE__; } } my $v = myClass->new(myID => time , myName => 'DC'); $v->hello; $v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
With MooseX::Declare, we get a role keyword
#!/usr/bin/env perl use v5.18; use warnings; use MooseX::Declare; role myRole { has 'myID' => (is => 'ro'); has 'myName' => (is => 'ro'); method doMsg (Str $m) { say $m } } class myClass with myRole { method hello { say __LINE__.' Hello from myClass' } } my $v = myClass->new(myID => time , myName => 'DC'); $v->hello; $v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
The same is true with Moops
#!/usr/bin/env perl use v5.18; use warnings; use Moops; role myRole { has 'myID' => (is => 'ro'); has 'myName' => (is => 'ro'); method doMsg (Str $m) { say $m } } class myClass with myRole { method hello { say __LINE__.' Hello from myClass' } } my $v = myClass->new(myID => time , myName => 'DC'); $v->hello; $v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
And with p5-mop-redux
#!/usr/bin/env perl use v5.18; use warnings; use mop; role myRole { has $!myID is ro = 0; has $!myName is ro = ''; method doMsg ($m) { say $m } } class myClass with myRole { method hello { say __LINE__.' Hello from myClass' } } my $v = myClass->new(myID => time , myName => 'DC'); $v->hello; $v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
With Role::Tiny, we can't put attributes in the role
#!/usr/bin/env perl use v5.18; use warnings; package myRole { use Role::Tiny; sub doMsg { my($self, $m) = @_; say $m; } } package myClass { use Class::Tiny qw(myID myName); use Role::Tiny::With; with 'myRole'; sub hello { say __LINE__.' Hello from '.__PACKAGE__; } } my $v = myClass->new(myID => time , myName => 'DC'); $v->hello; $v->doMsg($v->myName .' Very nice! How much RAM is Eclipse using?');
Here myRole has only the doMsg method; we use Class::Tiny to stick the attributes directly into myClass. Then we consume the role with Role::Tiny::With.
That brings up another point we haven't even touched on: what happens when we mix and match all of these classes and roles? Like consuming Moo roles with Moose and vice versa.
Just like last week, this example it too small to really show the differences between the various systems. It doesn't even really show the difference between roles and inheritance. Suggestions on how to create a richer example without getting mired in details are welcome.
Recent Comments