----- Original Message ----- > From: Jesse Luehrs <d...@tozt.net> > On Fri, Mar 29, 2013 at 05:34:50AM -0700, Ovid wrote: >> ----- Original Message ----- >> >> > From: Lars Balker <l...@balker.dk> >> > >> > 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. >> 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. 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? Cheers, Ovid