Re: Announcement: Moose 2.0800 is released!

[email protected] (Jesse Luehrs)
Newsgroups perl.moose
Message-ID <[email protected]>
On Fri, Mar 29, 2013 at 08:04:31AM -0700, Ovid wrote:
> ----- Original Message -----
> 
> > From: Jesse Luehrs <[email protected]>
> > On Fri, Mar 29, 2013 at 05:34:50AM -0700, Ovid wrote:
> >>  ----- Original Message -----
> >> 
> >>  > From: Lars Balker <[email protected]>
> >>  > 
> >>  > As Jesse's earlier example showed, instead of excluding and 
> > aliasing,
> >>  > just refer to the methods directly within the roles:
> >>  > 
> >>  > use v5.10.0;
> >>  > { package R::Programmer; use Moose::Role; sub pay_rate {12} }
> >>  > { package R::Clerk;      use Moose::Role; sub pay_rate {10} }
> >>  > { package R::Employee;   use Moose;
> >>  >   with 'R::Programmer';
> >>  >   with 'R::Clerk';
> >>  >   has [qw/programming_hours drudgery/] => ( is => 'ro' 
> > );
> >>  >   sub paycheck {
> >>  >       my $self = shift;
> >>  >       return $self->R::Programmer::pay_rate * 
> > $self->programming_hours
> >>  >           + $self->R::Clerk::pay_rate      * $self->drudgery;
> >>  >   }
> >>  > }
> >>  > my $employee = R::Employee->new(
> >>  >     programming_hours => 15,
> >>  >     drudgery          => 25,
> >>  > );
> >>  > say $employee->paycheck;
> >> 
> >> 
> >>  With 'R::Programmer' and 'R::Clerk' composed on separate 
> > lines, you no
> >>  longer get compositional safety and roles become little more than
> >>  glorified mixins. These were problems that roles/traits were designed
> >>  to fix. This is not an improvement.
> > 
> > There's no need to actually compose them separately, things work just
> > fine if you compose them on the same line.
> 
> I think you may have misread the code. He composed them separately because if he composed them at the same time, he would get a conflict:
> 
>     Due to a method name conflict in roles 'R::Clerk' and 'R::Programmer', 
>     the method 'pay_rate' must be implemented or excluded by 'R::Employee' at ...
> 
> Thus, in this instance, he was forced to compose those roles
> separately (since "exclude" is going to be taken away) and lose
> compositional safety.

I did misread. In this case though, this is something that you shouldn't
even be allowed to do in the first place, and the fact that Moose allows
it is arguably a bug. You're consuming a role which provides a pay_rate
method, but then you aren't providing a pay_rate method yourself. This
entirely breaks the concept of a role interface as a contract.

> >>  And I should not have to hardcode the class names into my method
> >>  names. That's a hack that we sometimes fall back on to work around MI
> >>  limitations when you're trying to call an otherwise unreachable method
> >>  and now it's bubbling up into roles?
> > 
> > How is this meaningfully different? You're already hardcoding the role
> > names at the point where you consume them.
> 
> 
> For the same reason that any cutting-and-pasting is a bad idea: our
> role as programmers is to minimize code duplication as much as
> possible to ensure that when we do have to change something, we
> minimize the number of places where said change needs to be made. I
> would much rather switch the name of the role I'm using at the top of
> my class and know that things *just work* (again, as was part of the
> original intent of Smalltalk traits) instead of having to remember to
> do a search and replace for every place where I've had to hard-code a
> package name.
> 
> I could also easily see someone subclassing "Employee" and now having
> to remember that if they want pay_rate, it's
> either $self->R::Clerk::pay_rate or $self->R::Programmer::pay_rate .
> The subclass *shouldn't* have to know the implementation details of
> Employee to make this work. Piers' solution of using
> "*programmer_pay_rate = \&R::Programmer::pay_rate is" is ugly, but
> it's marginally better. However, that's the sort of scaffolding code
> that roles were (pardon the broken record) designed to handle. The
> tools to get this right are already in Moose, so I'm really confused
> about what's going on here.

You shouldn't ever need to access the individual implementations of
R::Clerk::pay_rate or R::Programmer::pay_rate except from within the
role or class that composes them. Doing otherwise also defeats the
purpose of a role as an interface contract. If you want to provide that
information, you should write it as an actual method

  sub programmer_pay_rate { shift->R::Programmer::pay_rate }

> I ask again: what benefit from removing 'alias' and 'exclude' is so
> strong that it's worth removing a tool that Moose has provided for
> years?

Every example you've given so far seems to be an abuse of the role
system. I still have yet to see an example where alias or excludes is
used in a way that makes sense (and as I mentioned before, I have never
once had a reason to use alias or excludes except to work around the
issue that is fixed in Moose 2.08).

-doy
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.