Re: Role Method Conflicts and Disambiguation

2005-11-01 Thread Yuval Kogman
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

2005-11-01 Thread Jonathan Lang
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

2005-11-01 Thread Luke Palmer
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

2005-11-01 Thread Rob Kinyon
 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

2005-11-01 Thread Jonathan Lang
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