Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

Re: Perl OO with Class::Struct

by davido (Archbishop)
on Dec 13, 2013 at 16:09 UTC ( #1067035=note: print w/replies, xml ) Need Help??

in reply to Perl OO with Class::Struct

I would suggest that the answer to #3 is:

Whether or not you've outgrown Class::Struct, in 2013 there is very little reason to use it. If you choose to use an OO helper (rather than writing OO by hand), and you want to stay light-weight and fast, use Moo. It's true that it is not core. But it is fast, minimal, and actively developed and used. And it's largely compatible with Moose classes.

With Moo, your example code above would look like this:

package Cat; use Moo; use MooX::Types::MooseLike::Base qw(:all); has name => ( is => 'ro', isa => Str ); 1; package Litter; use Moo; use MooX::Types::MooseLike::Base qw(:all); has cats => ( is => 'ro', isa => ArrayRef ); 1; package main; my $cat1 = Cat->new(name=>'Garfield'); my $cat2 = Cat->new(name=>'Felix'); my $litter = Litter->new(cats => [$cat1, $cat2]); for (@{$litter->cats}) { print $_->name . "\n" }

...but in this example Moo is doing more: It's assuring that the accessors "name" and "cats" can't be modified after the object has been instantiated. It's also assuring that "name" is a string.

But one real advantage is that instead of isa => ArrayRef, you could say:

isa => sub { my $param = shift; die "<<$param>> must be an array ref" unless ref $param eq 'ARRAY'; foreach my $element ( @{$param} ) { die "<<$element>> isn't a Cat object" unless ref $element eq 'Cat'; } }

Now your object instantiation verifies that all of the elements passed by Litter->new( cats => [ ... ] ) are Cats objects. You could even get more "general" by skipping the "ref $element eq 'Cat'" test, and instead allowing any sufficiently Cat-like object to pass:

die "<<$element>> must have a name attribute" unless $element->can('name');

With Moo you could also define a BUILDARGS subroutine that silently drops any elements from cats => [...] that don't have a "name" attribute.... if you want that behavior instead.

Now, going back to the MooX::Types::MooseLike::Base example, even these constructs are possible:

isa => ArrayRef[ InstanceOf['Cat'] ]

And if you want your Litter class to accept any object that has a name attribute (in other words, a litter of bobcats would be fine too, as long as they have a name attribute), you can...

isa => ArrayRef[ HasMethods['name'] ]

Which provides clear semantics and avoids complexity. Moo makes this sort of thing pretty simple. Moose, being Moo's big uncle also has similar syntactic sugar. But Moo is so light-weight it's a great fit for small projects.

Update: So putting it all together, here's your original code with the Moo and MooX::Types::MooseLike::Base syntax:

package Cat; use Moo; use MooX::Types::MooseLike::Base 'Str'; has name => ( is => 'ro', isa => Str ); 1; package Litter; use Moo; use MooX::Types::MooseLike::Base qw( ArrayRef HasMethods ); has cats => ( is => 'ro', isa => ArrayRef [ HasMethods ['name'] ] ); 1; package main; my @cat_names = qw( Garfield Felix ); my $litter = Litter->new( cats => [ map { Cat->new( name => $_ ) } @cat_names ] ); print $_->name . "\n" for @{ $litter->cats };

Updated: Removed quotes from isa => checks since Moo requires a subref, and since that's what MooX::Types::MooseLike::Base provides.


Replies are listed 'Best First'.
Re^2: Perl OO with Class::Struct
by tobyink (Abbot) on Dec 13, 2013 at 16:24 UTC

    Actually, isa => 'ArrayRef' doesn't work in Moo at all. (Unless you also use MooX::late which is my Moose/Moo compatibility shim.)

    In Moo, isa needs to be a coderef, or an object overloading &{}.

    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

      You're right; I should have said, "isa => ArrayRef", which is compatible with Moo when used with MooX::Types::MooseLike::Base.

      Personally I always just use sub { ... } so that I can take finer control.

      I'll update my post to remove the quotes from the isa check.


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1067035]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2017-04-29 11:43 GMT
Find Nodes?
    Voting Booth?
    I'm a fool:

    Results (531 votes). Check out past polls.