Re: Role Method Conflicts and Disambiguation
On Fri, Oct 28, 2005 at 14:19:46 -0400, Stevan Little wrote: Yuval, On Oct 28, 2005, at 10:59 AM, Yuval Kogman wrote: On Thu, Oct 27, 2005 at 22:19:16 -0400, Stevan Little wrote: Now, at this point we have a method conflict in suspension since (according to A/S-12) method conflicts do not throw an error until a role is composed into a class. This means that when I do this: class MyClass does FooBar {} an exception is thrown. Unless of course MyClass has a foo method, which will disambiguate the conflict. My question then is, can FooBar (the role) disambiguate the foo conflict? IMHO yes, but it doesn't have too. It should be able to leave it to the class to decide. If we allow the class to decide if things break or not, then we potentially allow for the system to be in a very unstable state. A method conflict means that neither method gets consumed, and at that point we have a gapping hole in our class. And compilation will not finish unless the class plugs the hole... role a; role b; role c does a does b; class d does c; If there is a conflict at c, it might be a conflict that c knows how to resolve, or it might be a conflict that c's documentation says the user has to decide on, depending on what they prefer. What I'm saying is that the hole in c can be consumed by d, and if it isn't plugged in either c or d, you get an error. I think it's useful from a role perspective, because that way you can let the user decide on some conflicts. While I can't think of an example, I don't think there is much risk - this doesn't take away functionality. The only issue is that you can compile a role with a conflict and it doesn't complain till you actually use the role (this should be taken care of by writing the simplest of tests for your role). It does open doors for higher complexity composition. Especially if you have a deep hierarchy of role consumption: a b c d \ / \ / e f \- g -/ (role g does e does f, e does a, does b...) Let's say that a and b conflict at 2 points. E can resolve one of them, and leave the other one for g to decide. Perhaps methods in f are used to resolve e with dynamic dispatch: role g does e does f { method conflicts_in_a_and_b ($arg) { given .method_from_role_f($arg) { when Condition { .a::conflicts_in_a_and_b($arg) } defualt { .b::conflicts_in_a_and_b($arg) } } } } This is, IMHO legitimate use. The only restriction should be that when runtime begins no class (or anything that can be instantiated) is allowed to still have a conflict.; In the end, we will have probably looked inside every method defined in Foo, Bar, FooBar and Baz in order to properly write MyClass2. IMHO, this is sort of defeating the usefulness of roles at this point. I disagree - you have to know what a role is actually giving you to exploit it. Too much black boxing makes your programming language seem like a Kafka story. Why? does it introduce bugs? ;-P If you can't see at all into the code you use you eventually run into problems like the shlemiel the painter algorithm for C strings (google to find refs for that, too long to explain here). Frequently when using library code whose documentation is not perfect (and in opensource almost no documentation is ever perfect) I have a great privilige - search.cpan.org has a one click path to seeing the source code of any module i'm considering to install. This allows me to see how something works, estimate how hard it will be to extend it if the need should arise, assess the quality of the code, and make sure I understood things correctly. This spirit of openness should be maintained. You don't have to take apart a role and recompose it and what not, breaking encapsulation. But you should be able to fudge it slightly, because the author of the role might not be getting paid to fix it to your needs, and you may have to get slightly hackish. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me whallops greyface with a fnord: neeyah!!! pgpVo7ZfRizkn.pgp Description: PGP signature
Re: Role Method Conflicts and Disambiguation
Yuval Kogman wrote: Stevan Little wrote: If we allow the class to decide if things break or not, then we potentially allow for the system to be in a very unstable state. A method conflict means that neither method gets consumed, and at that point we have a gapping hole in our class. And compilation will not finish unless the class plugs the hole... role a; role b; role c does a does b; class d does c; If there is a conflict at c, it might be a conflict that c knows how to resolve, or it might be a conflict that c's documentation says the user has to decide on, depending on what they prefer. What I'm saying is that the hole in c can be consumed by d, and if it isn't plugged in either c or d, you get an error. True enough; but it needn't be true that d have the same tools available to resolve the conflicts that c has. There are three ways that a role can deal with a conflict: 1. choose one of a set of available methods to call its own. 2. create a version of its own. 3. pass the buck. In the first case, the question is how we define the set of available methods: do we make the full hierarchy of ancestors available to the role, or do we say that only the immediate parents are available? Another way to put this would be: should the DOESA list be treated as public or private? (My preference: the DOESA list should be private. You don't lose any capabilities by doing so, other than the capability to access stuff not explicitly declared - a capability that roles don't need, and probably shouldn't have.) If DOESA is private, then d won't have access to anything from a or b without explicitly including them in its own DOESA list. This seems to be restrictive, and it is - but only in the same way that making an attribute private is restrictive. The second case is pretty straightforward. In the third case, I'd be inclined to say that passing the buck is equivalent to creating an undefined version of your own - that is, not addressing a conflict involving method x is equivalent to saying method x ($arg) { ... }. IOW, a class that does a role that passed the buck is faced with an undefined method complaint if it doesn't do something about it, not an unresolved conflict complaint. -- Jonathan Dataweaver Lang
Re: Role Method Conflicts and Disambiguation
On 11/1/05, Jonathan Lang [EMAIL PROTECTED] wrote: In the third case, I'd be inclined to say that passing the buck is equivalent to creating an undefined version of your own - that is, not addressing a conflict involving method x is equivalent to saying method x ($arg) { ... }. IOW, a class that does a role that passed the buck is faced with an undefined method complaint if it doesn't do something about it, not an unresolved conflict complaint. Well, I think that the two are pretty much the same thing. I mean, you have to do the same thing to fix it: define your own version. Given that, it's probably best to call it unresolved conflict, so people don't stare at the role they are including and its definition of the method and yell at the compiler IT'S RIGHT THERE!. It's just an error message issue. Luke
Re: Role Method Conflicts and Disambiguation
1. choose one of a set of available methods to call its own. 2. create a version of its own. 3. pass the buck. #1 and #2 are identical. Stevan and I have always viewed #1 as a special case of #2. If you want to choose a method to call, then create a method of your own and have it wrap the one you want to call. The benefit here is that you can do more than just pick a method. Let's say that you have a conflict and the correct behavior is to do them all, but in a certain way. Or, maybe the correct behavior is to provide a limited API over one version. Maybe, there'll be some sugar to allow #1 to be its own syntax, but it should be viewed as a #2. Rob
Role Method Conflicts and Disambiguation
Rob Kinyon wrote: 1. choose one of a set of available methods to call its own. 2. create a version of its own. 3. pass the buck. #1 and #2 are identical. Stevan and I have always viewed #1 as a special case of #2. If you want to choose a method to call, then create a method of your own and have it wrap the one you want to call. The benefit here is that you can do more than just pick a method. Let's say that you have a conflict and the correct behavior is to do them all, but in a certain way. Or, maybe the correct behavior is to provide a limited API over one version. Maybe, there'll be some sugar to allow #1 to be its own syntax, but it should be viewed as a #2. You're right. But this obscures the point that I was trying to make: we need to decide what set of methods are available when disambiguating. Is the DOESA list public or private? Should the role be able to look up any public method that any of its ancestors have, or should it be restricted to just the methods that its parent roles have? Given the flattened nature of composition, I feel that the latter is more appropriate. -- Jonathan Dataweaver Lang