Perl-Apollo / Corinna

Corinna - Bring Modern OO to the Core of Perl
Artistic License 2.0
157 stars 19 forks source link

Roles Feedback #9

Closed Ovid closed 2 years ago

Ovid commented 4 years ago

Use this issue to provide feedback on the Roles Proposal.

haarg commented 4 years ago

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.

HaraldJoerg commented 4 years ago

I have questions about the behavior:

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 4 years ago

@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 3 years ago

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 3 years ago

@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 3 years ago

@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 2 years ago

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