On 29 March 2013 09:13, Ovid <curtis_ovid_...@yahoo.com> wrote:
> In short:
>
> 1. Allowing a role to silently override a consumed role's methods moves Perl 
> roles even further away from Smalltalk-style traits and its associative and 
> commutative guarantees.

Given that, unless you implement 'pay_rate' in your consuming role,
then 'with qw(R::Programmer R::Clerk)' is going to blow up because you
haven't resolved the conflict I'm not entirely sure your claim has any
validity here.

>
> Regarding plans to remove 'alias' and 'excludes':
>
> 2. Intending to remove the aliasing and excluding composition tools removes 
> tools that allow finer control over how you consume your objects.

At the point you compose the two conflicting roles (using with
qw(R::Programmer R::Clerk) you are required to resolve the conflict
and, at that point, you know the fully qualified names of the methods
that are in conflict, you've got all the fine control you could
desire. Yes, it's going to look ugly, what with the long names and
all, but if that's _really_ a problem and excludes/alias have gone
away, you still have possibilities like this open to you:

    with qw(R::Programmer R::Clerk);
    *programmer_rate = *R::Programmer::pay_rate;
    *clerk_rate = *R::Clerk::pay_rate;

    sub pay_rate {
        my $self = shift;
        confess "Liskov Substitution Principle violation in progress"
            or return ( $self->programmer_rate * $self->programmer_hours
                      + $self->clerk_rate * $self->clerk_hours ) /
$self->total_hours;
    }

And yes, it's horribly ugly, but your modelling here is horribly ugly
too and ugly things should be ugly. And what it buys me in exchange is
Roles that don't surprise me all the bloody time by not doing the the
Right Thing. The new system for resolution boils down to a pretty
simple mechanism:

When composing one more more roles into a target package then, for any
given $method of those roles we apply the following logic:

    $method_choice = $target->can($method)
      or do {
          @possibilities = map { $_->can($method) || () } @roles;
          confess "Bad programmer, no cookie!" unless @possibilities == 1;
          $possibilities[0];
      }

Straightforward, consistent, predictable. What's not to like?

This means that, in the 90% case of two roles conflicting (we want to
choose the methods from one of them) we can write:

    use (Role::Winner);
    use (Role::RunnerUp);

And in the ickier cases, we can still control how things get resolved,
but the code will be icky. Because that's okay, because the sooner our
bad modelling forces us to write icky code, the sooner we can realise
that it's bad modelling and fix the model.

> 3. Removing certain use cases for role composition and forcing developers to 
> fall back on delegation is a significant performance hit.

Not sure I'm understanding which use case has gone away.

Reply via email to