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:54
Subject:
Re: Why to use Moose roles ever?
Message ID:
CAATnKFAd6DsGHXcMj3TkfzK=Z_kjY6knF3Hs1G-eEAiaVjY1AA@mail.gmail.com
On 11 August 2016 at 16:36, Niall Young <niall@iinet.net.au> wrote:
> On Thu, 11 Aug 2016, Kent Fredric wrote:
>
>> On 11 August 2016 at 15:43, Niall Young <niall@iinet.net.au> wrote:
>>>
>>> Not sure how your example applies here Karen, there is no foo() declared
>>> in
>>> MyClass only a foo method modifier, and MyRole's foo() doesn't appear to
>>> be
>>> executed from your output?
>>
>>
>> In the example she gave, the point was not to call MyRole's foo, only
>> to replace it. ( Because Roles prohibit replacement by default, its a
>> conflict that must be manually resolved )
>
>
> The OP's goal was to override MyClass's foo, not MyRole's foo.

OP:
> Moose roles have some limitations, such as inability to override a
> method in a class which "with"es the role.

Overriding a method in a parent class that composes a role is
identical in practice
to overriding a method in a composed role.



{ package MyRole;
   use Moose::Role;
   sub foo { return "In role" }
}
{ package MyClass;
   use Moose;
   with "MyRole";
}
{
   package MyOtherClass;
   use Moose;
   extends "MyClass";
   around "foo" => sub { ... }
}

Done.

MyClass composes MyRole so "MyRole::foo" is now "MyClass::foo";

"around" retrieves MyClass::foo ( which was MyRole::foo ) and
wraps/overrides it.


>
>> If one wants to call MyRole::foo in the new MyClass::foo, this is done:
>>    around foo => sub {
>>       my ( $orig, $self, @args );
>>       return join q[, ],  'I came from the class', $self->$orig( @args );
>
>
> It seems cumbersome, and makes Classes aware of and dependent on the
> existence of Role(s).
>
> Like the OP I struggled to come up with a good way to take advantage of
> Roles, as nice as they are in principle there are some fundamental
> constraints which make applying them (and enjoying their inherent benefits,
> or start approaching the benefits of Traits) problematic.
>
> Moose cleans up Classes tremendously, which by itself is a pretty huge win
> (not to mention access to the MOP at runtime etc.) but Roles .. like the OP
> I'm still struggling to find a use-case which lives up to their potential.
> I really, really want to use them, but they come with their own issues, or
> costs which seem to negate or outweigh their benefits.  That's not a
> criticism btw, just an observation.

But this is good, really, you shouldn't be "trying to find a use for
it", that's sort of coding-by-patterns and it never ends well.

You should just know what its for, so when a situation arises you need
it, its there.

They're usually the cases where you *dont* want the originator of the
sub to turn up in @ISA

And they're usually similar cases to where you might reach for
Import/Export if you're writing functional interfaces.

( After all, "Roles" are basically "Imports, but methods" with a lot
of conveniences on top )

For instance, perhaps you want all your classes to have a "->dump"
method for debugging purposes, where a basic implementation can be
shared, and the definition can be extended on a class-by-class basis
to give better results where needed.

Making every class in your project inherit a "Debugger" class is just
going to create a horrible mess in the inheritance chains.

Writing that method from scratch in every package is horrible, and you
have no tools to identify which packages have not just a dump method,
but a dump method that conforms to the API you expect it to ( ie: 3rd
party modules may have their own dump methods that might turn up in
places that act differently )

Here, you can just create a Debugger role , and apply it to all your
packages via "WIth", and then "around dump => " in places you need to
augment the results.

Then when comes time to consume it, you can just check "hey, this
class is one of the ones that does this thing the way I expect" by
asking $object->DOES("My::Debugger")

and then when that returns true, you know that you can call
$object->dump and have it behave the way you expect, mostly.

Because "with" not only indicates "Please compose X" , but advertises
"I conform to interface X"

That advertisement can of course be false still, but its more reliable
than a blind $object->can('dump') # good enough?

You never know, one of those might be "trigger coredump and exit" ;)


-- 
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