Perl-Apollo/Corinna

Roles Feedback

Closed this issue · 7 comments

Ovid commented

Use this issue to provide feedback on the Roles Proposal.

haarg commented

I don't find arguments about silently changing behavior due to classes overriding role methods particularly convincing. Inheritance has the exact same issue.

Roles probably need to be able to provide behavior like the ADJUST and DESTRUCT methods shown elsewhere. Having these be "methods" may not be the best approach. As mentioned elsewhere, the pattern used in Moose/Moo looks like:

sub BUILD {}
after BUILD => sub { ... };

This is not obvious to do. Also this requires method modifiers, which are excluded from this proposal for roles. Having them be separate keywords or something similar may make sense. But allowing roles to have behavior tied to construction or destruction prevents them from being commutative. This includes attributes with immediate defaults. But I don't think preventing roles from having any construction time behavior is viable.

Excluding method modifiers to preserve commutative properties that are already not guaranteed is a mistake, I believe.

I have questions about the behavior:

  • Does a role have access to the slots or other innards of the consuming class?
  • Is a private method sufficient to fulfill a requires predicate for a role?

Consider the example from the classes page:

class Customer v1.31.0 isa Person does Serializable::JSON { ...; }

Serialization makes sense for a role. But how to implement this role? Somehow the role needs to collect the relevant data from the object. With Moo*, well, we know it's just a hash reference, so just dump that and on de-serialization load that dump and bless it into the object's class. Pretty generic, reusable stuff. Breaking encapsulation? Who cares, it works.

With Cor such hackery is gone. With a required method a role could force the class to provide its content in a serializable fashion, it could be a private method to avoid a bloated interface. Also, de-serialization raises questions, but that's outside the scope of the "Roles" topic.

Ovid commented

@HaraldJoerg A roles does not have access to the slots or other innards of the consuming class. Instead, if that class provides public methods (even via :reader or :writer), then the role can use those.

Yes, private methods should be sufficient for the requires predicate.

maros commented

I miss a 'does' (or similar) method to check on an object if a particular behavior/interface is supported. One could use 'can' instead and check for a particular method name, but this is prone to accidental name conflicts. Not sure if this belongs into the role rfc, though.

Ovid commented

@haarg wrote:

I don't find arguments about silently changing behavior due to classes overriding role methods particularly convincing. Inheritance has the exact same issue.

Given that roles were invented and later formalized to fix the problems with inheritance, I think that should answer the question. Heck, this is enough of an issue with inheritance that Java introduced the @Override annotation to instantly let developers know that something was going on.

In traits, the researchers modified the Smalltalk browser to signal to developers that a method was "shadowing" a role method. It was never intended to be silent action at a distance. Wondering why role isn't functioning the way I expect because I've silently replaced the fun method isn't fun. Corinna is supposed to be fixing problems, not holding on to old problems.

Excluding method modifiers to preserve commutative properties that are already not guaranteed is a mistake, I believe.

I believe we've gotten to the point where I reluctantly agree with this, but we've punted on this behavior for V1. Given that the majority of OO languages out there seem to be able to do without method modifiers suggests to me that we should at least see what comes out of this for Corinna.

Your other points about ADJUST and DESTRUCT are taken. They're now included in roles (darn it), along with slot initialization, but I don't think they necessarily break commutativity unless they operate on conflicting state (though there's a high chance of that)

Ovid commented

@HaraldJoerg asked:

Does a role have access to the slots or other innards of the consuming class?

No.

Is a private method sufficient to fulfill a requires predicate for a role?

Not at this time, because a role cannot see private methods in other namespaces.

At some point we'll need to address this. Java has a similar issue with interfaces in that they can't do much with protected methods, so everything via interfaces is public. This, I think, is a mistake. However, I want to tread lightly here because it seems like this is easy to get wrong. Thus, is seems more of a V2 feature.

Ovid commented

With reluctance, closing this because it doesn't seem to impact the accepted MVP.