develooper Front page | perl.moose | Postings from August 2016

Re: Why to use Moose roles ever?

Thread Previous | Thread Next
From:
Kent Fredric
Date:
August 11, 2016 04:10
Subject:
Re: Why to use Moose roles ever?
Message ID:
CAATnKFDuppzBAPOYRH2JELWfSQsfwhVQgsfcL46TpVw--Yuu4g@mail.gmail.com
On 11 August 2016 at 09:25, Karen Etheridge <perl@froods.org> wrote:
>> Moose roles have some limitations, such as inability to override a
> method in a class which "with"es the role.
>
> This is false. For example:
>
> {
>     package MyRole;
>     use Moose::Role;
>     sub foo {
>         'I came from the role';
>     }
> }
>
> {
>     package MyClass;
>     use Moose;
>     with 'MyRole';
>     around foo => sub {
>       'I came from the class';
>     };
> }


In fact, the above inherent conflict requiring explicit handling is
seen as a "feature" of Moose Roles: It prohibits accidentally
overriding classes in an "external" context, and makes it glaringly
apparent that a given sub is an overrride.

With standard inheritance, you have to use tools to introspect the
@ISA graph at runtime[1] and *then* you know which methods are
overridden and where they parent to.

The simplest description I have of Roles in advantage to Inheritance
is their design makes it easier to reason about what it is your code
does, it makes it clearer from a developers perspective what the
composition is, and simplifies the logic required for deep
composition.

Because unlike Multiple inheritance where the composition is performed
dynamically by the perl interpreter at runtime, with arbitrary depth
@ISA's, Role composition is done in layers, where each layer is
composed and made immutable prior to being composed into the next.

This is very different from MI, where the default intuition you'll
apply to reason about "what method is the next one" is pretty much
wrong, because counter-intuitively, if you mentally build a  method
resolution order for a given sub in a given class .... then compose
that given class into another, instead of the method resolution of its
resulting class being trivially represented in terms of its parts, it
is in reality unique to its parent, because MRO's are hard.

For example:

CHILD2::foo

CHILD1 isa CHILD2

CHILD1->foo therefore calls CHILD2::foo

You'd probably be prone to assuming that because of that:


PARENT isa CHILD1 , CHILD3

PARENT->foo therefore would call CHILD2->foo

But it might not.

It might call CHILD3::foo, or CHILD4::foo , depending on what CHILD3 does.

^^^ this stuff does my head in and I've spent quite a few hours
bashing my head over understanding exactly how it works, and even my
example case is probably wrong in some regard.

But the truism is that in large hierarchies,
mro::get_linear_isa(PARENT)  and mro::get_linear_isa(CHILD1) can very
much be very different from each other.

And then how they're different depends on which mro is assigned to each class.

For producing a MRO for PARENT, /only/ the MRO assigned to PARENT is
considered, even when composing its parents.

When producing a MRO for CHILD, /only/ the MRO assigned to the CHILD
is considered, even when composing  its parents.


And this stuff will make your head hurt and your code confusing unless
you have reams of tools at your disposal to answer such questions, and
you know to use the tools.

Roles are, by comparison, much more intuitive.

But they come at a technical price: Lots of anonymous subs all over
the place gluing everything together.

Which makes understanding traversal *from code* harder, and makes
introspection tools somewhat "blind" to the dark magic that is going
on.


I'd probably be inclined to argue that neither MI or Roles are very
fun to use, and they're more often abused than used, so if you feel
yourself reaching for them, ask yourself "do I really need to?".

And I'd be inclined to argue maybe you should consider using
attributes with delegation instead of roles and inheritance.

That choice has its own limitations of course, notably the additional
indirection comes at a performance price.

But it also does away with the sorts of crazy people tend to end up
asking for: Instance Roles.

Because its much nicer to just replace an attribute with an object of
a different class than it is to apply a role to an instance to achieve
the same effect :)



hth

-- 
Kent

KENTNL - https://metacpan.org/author/KENTNL

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About