Re: Role Method Conflicts and Disambiguation

2005-11-03 Thread Stevan Little


On Nov 2, 2005, at 9:02 PM, Jonathan Lang wrote:

Let's say you have this:

  role A {method foo() { code1; } }
  role B {method foo() { code2; } }
  role C does A does B {
method foo() { A::foo(); }
method bar() { B::foo(); }
  }

Should the following be valid?

  role D does C { method foo() { B::foo(); } }

IMHO, it shouldn't, because D doesn't do B.


Not valid in what way? Should this be a fatal error?

Are you implying that B is not local to D, so it cannot use it? that  
somehow disambiguation must be done using one of your local subroles  
only?


I think this is too restrictive, D should be able to freely  
disambiguate or override using anything it want's to. It need not be  
related at all to it's subroles.


Stevan


Re: Role Method Conflicts and Disambiguation

2005-11-03 Thread Rob Kinyon
 On Nov 2, 2005, at 9:02 PM, Jonathan Lang wrote:
  Let's say you have this:
 
role A {method foo() { code1; } }
role B {method foo() { code2; } }
role C does A does B {
  method foo() { A::foo(); }
  method bar() { B::foo(); }
}
 
  Should the following be valid?
 
role D does C { method foo() { B::foo(); } }
 
  IMHO, it shouldn't, because D doesn't do B.

Additionally, D most certainly does B. That it does B through a proxy
is irrelevant. Think about it this way - if you had Surfer and Dog and
SurferDog does Surfer does Dog, wouldn't you want to know that
class ScoobyDoo does SurferDog does Dog?

If SurferDog doesn't do Dog, how would ScoobyDoo do Dog?

 I think this is too restrictive, D should be able to freely
 disambiguate or override using anything it want's to. It need not be
 related at all to it's subroles.

To further expand on this, D's disambiguation of method foo() could be:

  role D does C { method foo() { Completely::Unrelated::foo() } }

Rob


Re: Role Method Conflicts and Disambiguation

2005-11-03 Thread TSa

HaloO,

Rob Kinyon wrote:

On Nov 2, 2005, at 9:02 PM, Jonathan Lang wrote:


Let's say you have this:

 role A {method foo() { code1; } }
 role B {method foo() { code2; } }


I think, A and B might just be aliases to the *identical* structural type
because the only constraint that both roles impose on their implicit type
parameter is the presence of a method foo() on the type of just this
parameter. The implementation parts are of course different. In other words
the roles A and B are interchangable as far as the structural type checker
is concerned! That is there is a

  theory T{^R} { multi foo (^R) {...} }

  A ::= T{A};
  B ::= T{B};

  A::foo.block ::= code1; # or however .block is spelled
  A::foo.block ::= code2; # or { code2; } ?



 role C does A does B {
   method foo() { A::foo(); }
   method bar() { B::foo(); }
 }

Should the following be valid?

 role D does C { method foo() { B::foo(); } }

IMHO, it shouldn't, because D doesn't do B.



Additionally, D most certainly does B. That it does B through a proxy
is irrelevant. Think about it this way - if you had Surfer and Dog and
SurferDog does Surfer does Dog, wouldn't you want to know that
class ScoobyDoo does SurferDog does Dog?


Semantic wise or type wise?



If SurferDog doesn't do Dog, how would ScoobyDoo do Dog?


Assuming that the type system supervises the constraint addition
in role composition, a meta information lookup on SurferDog should
yield all you need to know about what kind of thing it is!
Just think of electrons and the double slit, if you don't require
them to know through which slit they passed, they don't bother to
remember it ;)



I think this is too restrictive, D should be able to freely
disambiguate or override using anything it want's to. It need not be
related at all to it's subroles.


Well, it can't step out of the frame that the constraints of C impose.
Actually it can because not all contstraints are computer enforceable
but it shouldn't for social reasons.



To further expand on this, D's disambiguation of method foo() could be:

  role D does C { method foo() { Completely::Unrelated::foo() } }


Yes, of course. But these are the boring cases. More interesting is
something like

  role X
  {
  method foo (: XA $a, XB $b -- XC ) {...}
  }

  role Y does X
  {
  method foo (: YA $a, YB $b -- YC ) {...}
  }

where the definition of Y should succeed only iff Y::foo : X::foo
which requires YC : XC and (XA,XB) : (YA,YB) where : denotes the
subtype relation.
--


Re: Role Method Conflicts and Disambiguation

2005-11-02 Thread Jonathan Scott Duff
On Tue, Nov 01, 2005 at 04:02:04PM -0800, Jonathan Lang wrote:
 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? 

People keep using the word hierarchy when talking about roles and I
keep thinking that it is the one word that definitely does NOT apply.
Heirarchies are for classes and inheritance relationships, not roles
and composition.

In my world view, a role that is composed of two other roles has full
view of the methods/attributes defined in the roles that compose it
because the landscape is quite flat. There are no hills and valleys.
When it finally comes down to composing into a class, the class sees
all of the methods/attributes provided by each and every role even the
role inside a role inside a roles.

 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.

When you say:

role A { ... }
role B { ... }
role C does A does B { ... }
role D does C { ... }

roles A and B are composed into C at compile time.  If both A and B
define a method foo(), then there is a conflict (immediately, at
compile time) unless you've somehow told perl that it should defer
composition until it's actually composing classes.

What's really at question I think is whether the _default_ is to compose
immediately or to postpone composition until there's a class to compose
into. If you have roles that are never composed into classes, then it
won't matter if there's a conflict as you can't instantiate a role (not
without first turning it into a class). So, on one hand it does make
sense to defer composition until there's a class to compose into. But
it also makes sense to deal with composition conflicts incrementally
too (as roles are composed into other roles).

 The second case is pretty straightforward.

And isomorphic to the first case as it is the resolution to the first
case.

 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.

Nah, the third case is ye olde standard conflict, just perhaps occurring
at a different space+time than had the roles been composed immediately.

-Scott
-- 
Jonathan Scott Duff
[EMAIL PROTECTED]


Re: Role Method Conflicts and Disambiguation

2005-11-02 Thread Yuval Kogman
On Wed, Nov 02, 2005 at 16:37:29 -0600, Jonathan Scott Duff wrote:
 On Tue, Nov 01, 2005 at 04:02:04PM -0800, Jonathan Lang wrote:
  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? 
 
 People keep using the word hierarchy when talking about roles and I
 keep thinking that it is the one word that definitely does NOT apply.
 Heirarchies are for classes and inheritance relationships, not roles
 and composition.

Uh, roles are composed wrt to the hierarchy of who does who.

 In my world view, a role that is composed of two other roles has full
 view of the methods/attributes defined in the roles that compose it
 because the landscape is quite flat. There are no hills and valleys.
 When it finally comes down to composing into a class, the class sees
 all of the methods/attributes provided by each and every role even the
 role inside a role inside a roles.

The composition is basically mixin with some exceptions, but there's
still a hierarchy

 roles A and B are composed into C at compile time.  If both A and B
 define a method foo(), then there is a conflict (immediately, at
 compile time) unless you've somehow told perl that it should defer
 composition until it's actually composing classes.

Class composition also happens at compile time... There's no reason
to make the error occur too early for usefulness to be around. As
long as it's not too late ;-)

-- 
 ()  Yuval Kogman [EMAIL PROTECTED] 0xEBD27418  perl hacker 
 /\  kung foo master: : neeyah!



pgpABuzitn7pL.pgp
Description: PGP signature


Re: Role Method Conflicts and Disambiguation

2005-11-02 Thread Jonathan Lang
Jonathan Scott Duff wrote:
 People keep using the word hierarchy when talking about roles and I
 keep thinking that it is the one word that definitely does NOT apply.
 Heirarchies are for classes and inheritance relationships, not roles
 and composition.

 In my world view, a role that is composed of two other roles has full
 view of the methods/attributes defined in the roles that compose it
 because the landscape is quite flat. There are no hills and valleys.
 When it finally comes down to composing into a class, the class sees
 all of the methods/attributes provided by each and every role even the
 role inside a role inside a roles.

-snip-

 When you say:

 role A { ... }
 role B { ... }
 role C does A does B { ... }
 role D does C { ... }

 roles A and B are composed into C at compile time.  If both A and B
 define a method foo(), then there is a conflict (immediately, at
 compile time) unless you've somehow told perl that it should defer
 composition until it's actually composing classes.

Let's say you have this:

  role A {method foo() { code1; } }
  role B {method foo() { code2; } }
  role C does A does B {
method foo() { A::foo(); }
method bar() { B::foo(); }
  }

Should the following be valid?

  role D does C { method foo() { B::foo(); } }

IMHO, it shouldn't, because D doesn't do B.

--
Jonathan Dataweaver Lang


Re: Role Method Conflicts and Disambiguation

2005-11-02 Thread Luke Palmer
On 11/2/05, Jonathan Lang [EMAIL PROTECTED] wrote:
 Let's say you have this:

   role A {method foo() { code1; } }
   role B {method foo() { code2; } }
   role C does A does B {
 method foo() { A::foo(); }
 method bar() { B::foo(); }
   }

 Should the following be valid?

   role D does C { method foo() { B::foo(); } }

 IMHO, it shouldn't, because D doesn't do B.

Of course it should.  To me, role D does C says, not anything that
does D must do C, but anything that does D does C.

It makes sense if you think of them as interfaces.  Say you have a
role Complexifiable (that is, this thing can behave like a complex
number).  Then you have:

role Numifiable does Complexifiable {
...
}

Complexifiable is just an abstraction that is used rarely; most things
will implement Numifiable.  But if you can behave like a real number,
certainly you can behave like a complex number.  But you don't want
people to have to say:

class Foo {
does Complexifiable;  # wtf?  what does that mean
does Numifiable;
...
}

Haskell makes a distinction between the two cases we're talking about here:

-- You need to be Complexifiable before you can be Numifiable
class (Complexifiable a) = Numifiable a where
...

-- Anything that is Numifiable is also Complexifiable
--  (by these rules):
instance Numifiable a = Complexifiable a where
...

To me, does is much more like the latter.  Maybe we have constraints
on roles that can do the former[1]:

role Numifiable {
where Complexifiable;
...
}

Or maybe we don't, and if you need them to implement Complexifiable
first, you just leave some methods undefined that they have to define
themselves, thus completing the interface.  I was always annoyed at
Haskell because I had to define an instance of Eq before I could
define an instance of Ord, even though Ord's algebra implies that I
can compare things for equality (and especially, since Ord defines a
total order, that a = b and b = a implies a = b, so it could have
implemented that for me).

It kind of seems like a Perlish thing to do to blur the two behaviors
together.

Luke

[1] Which is just this theory, without any extensions:

theory Numifiable{^T} = Complexifiable{^T} {
...
}

So it would just be sugar in any case.


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


Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Yuval Kogman
On Thu, Oct 27, 2005 at 22:19:16 -0400, Stevan Little wrote:
 Hello all,
 
 I have a question about method conflict resolution works for roles,  and I 
 cannot seem to find this in any 
 of the Apoc/Syn documents.
 
 Here is the basic issue:
 
 role Foo {
  method foo { ... }
  method bar { ... }  # we will use this later :)
 }
 
 role Bar {
  method foo { ... }
 }
 
 role FooBar {
  does Foo;
  does Bar;
 }
 
 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.

 role FooBar {
  does Foo;
  does Bar;
  method foo { ... }
 }
 
 Now, on the surface this seems obvious, of course the FooBar role  should be 
 able to disambiguate. However, 
 when we expand the example  other issues show up.
 
 role Baz {
  does Foo;
 }
 
 class MyClass2 does FooBar does Baz {}  # Will this die?

splice

 But thats not all, we have a potential problem with foo again. Baz  will 
 provide foo from Foo, but FooBar 
 will provide it's own foo  (which we used to disambiguate). So our 
 disambiguation is not  ambiguated 
 again.

/splice

yes, since the methods are coming from different context, and they
may have different meanings. While FooBar::foo resolves the conflict
from the assimilation of Foo::foo and Bar::foo, it does it only
within FooBar.

If, OTOH we have a diamond inheritence:

role A { method foo { ... } }
role B does A {};
role C does A {};
class D does A does B { };

I'm not sure we need to resolve the conflict.

 Now, since MyClass2 actually does Foo twice, does that mean bar  creates a 
 conflcit? Since bar would be 
 found through FooBar and Baz.  I would think the answer here would be no, and 
 that we would build  some 
 kind of unique list of roles so as to avoid repeated consumption  like this.

No conflict - an assimilated role is identicle to itself even
through different paths since it doesn't get access to private or
protected member data of it's consuming roles.

If, on the other hand, we have

role X trusts Foo does Foo {
has $:foo;
}

role Y trusts Foo does Foo {
has $:foo;
}

role Foo {
method foo {
$:foo++;
}
}

class C does X does Y { }

there is a conflict, because Foo is reaching into either X's private
member $:foo or Y's private member $:foo (btw, they should never
conflict with each other).

The moment a method will have behavior that is different in two
different role consumptions it will be conflicting, but this will
only happen to a method from the same class if it has some private
symbols resolved at role composition time using class friendship.


I think it is ambiguous, s

 A (deceptively) simple solution to this is that MyClass2 needs to  
 disambiguate. But this means that our 
 roles are not really black  boxes anymore. In order to properly disambiguate 
 this we need to know  where 
 all the foo methods are coming from (Foo, Bar and FooBar), and  potentially 
 what is inside these foo 
 methods (especially in the case  of FooBar since it is attempting to 
 disambiguate, it's behavior could  be 
 very specific). It probably would also become important to know  what other 
 methods foo interacts with 
 since we potentially have 3  different expected versions of foo.

method foo is Foo::foo;

or

method foo (*$a) { ./Foo::foo(*$a) }

or

foo ::= Foo::foo;

 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.

 So what do you all think??

Role method conflicts should only be dealt with if the user knows
what the roles are actually doing anyway. This will probably be
familiar code, and if not it warrants familiarity.

I don't think we can let the user use library code without being
aware of the library code internals at all. Abstraction that works
like this is usually either crippled or useless. 90% of the time you
don't want to know, but there are exceptions.

-- 
 ()  Yuval Kogman [EMAIL PROTECTED] 0xEBD27418  perl hacker 
 /\  kung foo master: /me sushi-spin-kicks : neeyah



pgpuXeiEdVhEc.pgp
Description: PGP signature


Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Jonathan Scott Duff
On Thu, Oct 27, 2005 at 10:19:16PM -0400, Stevan Little wrote:
 I have a question about method conflict resolution works for roles,  
 and I cannot seem to find this in any of the Apoc/Syn documents.
 
 Here is the basic issue:
 
 role Foo {
 method foo { ... }
 method bar { ... }  # we will use this later :)
 }
 
 role Bar {
 method foo { ... }
 }
 
 role FooBar {
 does Foo;
 does Bar;
 }
 
 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:

If we say that the roles Foo and Bar are composed into the role
FooBar and that method conflicts trigger an exception at composition
time (whether composed into a role or class), then your above
declaration of FooBar will trigger an exception and force the user to
resolve the conflict.

 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?
 
 role FooBar {
 does Foo;
 does Bar;
 method foo { ... }
 }
 
 Now, on the surface this seems obvious, of course the FooBar role  
 should be able to disambiguate. 

I agree. Methods declared explicitly in FooBar should trump methods that
have been composed into FooBar (just as it would if FooBar were a class)

 However, when we expand the example  
 other issues show up.
 
 role Baz {
 does Foo;
 }
 
 class MyClass2 does FooBar does Baz {}  # Will this die?

I think yes. FooBar has a method foo() and so does Baz. They may be the
same foo() underneath because that's how the FooBar role decided to
resolve the method conflict, but Baz doesn't know that. Though, the perl
compiler needs to keep track of the composition history of classes/roles
to provide useful error messages.

 Now, since MyClass2 actually does Foo twice, does that mean bar  
 creates a conflcit? Since bar would be found through FooBar and Baz.  
 I would think the answer here would be no, and that we would build  
 some kind of unique list of roles so as to avoid repeated consumption  
 like this.

In my world view it doesn't to Foo twice, it does FooBar (which is a
composed of Foo and Bar, but MyClass doesn't know the origin of the
methods) and it does Baz. Since the Baz role and the FooBar role have
the same methods because they were both composed of Foo, the perl
compiler will spit out some messages letting you know that
you've built a class from a doubly composed role.

But if you happen to do

class Foo does Bar does Bar { ... }

perl should be nice enough not to yell at you for doing the Bar role
twice.

In the case where really do want the added bits of the Baz role along
with the added bits of the FooBar role (including that disambiguation),
but perl is carping because most of the methods are the same (having
both been composed from Foo), then 1) it's probably a sign that you need
to refactor and 2) you can always use delegation to get the desired
behavior (assuming I'm correct in that you can delegate to specific
roles at composition time as a mechanism for disambiguation).

-Scott
-- 
Jonathan Scott Duff
[EMAIL PROTECTED]


Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Jonathan Scott Duff
On Fri, Oct 28, 2005 at 04:59:18PM +0200, Yuval Kogman wrote:
 If, OTOH we have a diamond inheritence:

You mean composition.  There is no role inheritance  :)

 
   role A { method foo { ... } }
   role B does A {};
   role C does A {};
   class D does A does B { };

I'm assuming you meant 

class D does B does C { ... }

 
 I'm not sure we need to resolve the conflict.

It depends on when composition happens. If A is composed immediately
into B and C as soon as the role is processed, then when D is being
composed, all it sees are a foo method from the B role and a foo method
from the C role.

If, however, roles aren't composed into other roles but only into
classes, then I think that

class D does B does C { ... }

would be equivalent to 

class D does A does B does C { ... }

since the roles B and C would carry the uncomposed A role along with
them.

  Now, since MyClass2 actually does Foo twice, does that mean bar  creates a 
  conflcit? Since bar would be 
  found through FooBar and Baz.  I would think the answer here would be no, 
  and that we would build  some 
  kind of unique list of roles so as to avoid repeated consumption  like this.
 
 No conflict - an assimilated role is identicle to itself even
 through different paths since it doesn't get access to private or
 protected member data of it's consuming roles.
 
 If, on the other hand, we have
 
   role X trusts Foo does Foo {
   has $:foo;
   }

Quoth A12:

It's not clear whether roles should be allowed to grant trust. In
the absence of evidence to the contrary, I'm inclined to say not. We
can always relax that later if, after many large, longitudinal, double-
blind studies, it turns out to be both safe and effective.

Has that changed?

Also, I don't think that role is something that can be trusted :)
A12/S12 only talk about trusting classes.

 
   role Y trusts Foo does Foo {
   has $:foo;
   }
 
   role Foo {
   method foo {
   $:foo++;
   }
   }
 
   class C does X does Y { }
 
 there is a conflict, because Foo is reaching into either X's private
 member $:foo or Y's private member $:foo (btw, they should never
 conflict with each other).

Er, there is only one $:foo.  X doesn't have any private members, nor
does Y (because they're roles).  Only C has private members.  So,
modulo the multiple composition of Foo, I don't think there's a
conflict.

-Scott
-- 
Jonathan Scott Duff
[EMAIL PROTECTED]


Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Yuval Kogman
On Fri, Oct 28, 2005 at 10:38:31 -0500, Jonathan Scott Duff wrote:
 You mean composition.  There is no role inheritance  :)

Oops ;-)

 I'm assuming you meant 
 
   class D does B does C { ... }

I always do that crap... =(

  I'm not sure we need to resolve the conflict.
 
 It depends on when composition happens. If A is composed immediately
 into B and C as soon as the role is processed, then when D is being
 composed, all it sees are a foo method from the B role and a foo method
 from the C role.
 
 If, however, roles aren't composed into other roles but only into
 classes, then I think that
 
   class D does B does C { ... }
 
 would be equivalent to 
 
   class D does A does B does C { ... }
 
 since the roles B and C would carry the uncomposed A role along with
 them.

I think of class inheritence (mixin or otherwise) as an N-ary tree
with ordered branches. That is, if you inherit two classes, one
comes after the other.

Roles differ because the tree is unordered and all roles assimilated
into a specific consumer must be treated equally (and will thus
conflict).

This allows roles to be more reusable than classes for generic
tasks, because if there is a conflict it usually implies namespace
clashes, not extended behavior.

Making everything into flattenned set is not a feature. It can be
the way things are really implemented later, but it's a lossy
representation - information about who 'does' who is lost.

In my opinion it's better to compose all role information in the
largest chunks possible (read - as late as possible in a given
linkage/compilation cycle) for the same reasons that JIT
optimizations are more effective: you know much more. However, care
must be taken to ensure that this is not too late, to the point that
the user does not get useful information.


 Quoth A12:
 
 It's not clear whether roles should be allowed to grant trust. In
 the absence of evidence to the contrary, I'm inclined to say not. We
 can always relax that later if, after many large, longitudinal, double-
 blind studies, it turns out to be both safe and effective.
 
 Has that changed?
 
 Also, I don't think that role is something that can be trusted :)
 A12/S12 only talk about trusting classes.

The role doesn't grant trust to a class that consumes it - it simply
says the role Foo has access to my guts when I assimilate it.
Class trust is something slightly more complex, since it's
inherited. I think that excert says It's not clear whether roles
should be allowed to make a class trust another class when they are
consumed.

  there is a conflict, because Foo is reaching into either X's private
  member $:foo or Y's private member $:foo (btw, they should never
  conflict with each other).
 
 Er, there is only one $:foo.  X doesn't have any private members, nor
 does Y (because they're roles).  Only C has private members.  So,
 modulo the multiple composition of Foo, I don't think there's a
 conflict.

Really? I didn't know that... In that case roles are broken... They
will need instance data (that doesn't conflict when it's private) to
support the methods they give their consumers.

Is there any good reason to not allow roles to introduce member data
into a class?

-- 
 ()  Yuval Kogman [EMAIL PROTECTED] 0xEBD27418  perl hacker 
 /\  kung foo master: /me whallops greyface with a fnord: neeyah!!!



pgp1rNFr6EZDh.pgp
Description: PGP signature


Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Stevan Little

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. IMHO we should not allow  
this to be decided by the user in any other way then to  
disambiguate,.. otherwise we should die very loudly.


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


So what do you all think??


Role method conflicts should only be dealt with if the user knows
what the roles are actually doing anyway. This will probably be
familiar code, and if not it warrants familiarity.


Agreed.


I don't think we can let the user use library code without being
aware of the library code internals at all. Abstraction that works
like this is usually either crippled or useless. 90% of the time you
don't want to know, but there are exceptions.


A little extreme, but I tend to agree with your point.

Stevan



Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Stevan Little


On Oct 28, 2005, at 11:17 AM, Jonathan Scott Duff wrote:

On Thu, Oct 27, 2005 at 10:19:16PM -0400, Stevan Little wrote:


I have a question about method conflict resolution works for roles,
and I cannot seem to find this in any of the Apoc/Syn documents.

Here is the basic issue:

role Foo {
method foo { ... }
method bar { ... }  # we will use this later :)
}

role Bar {
method foo { ... }
}

role FooBar {
does Foo;
does Bar;
}

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:



If we say that the roles Foo and Bar are composed into the role
FooBar and that method conflicts trigger an exception at composition
time (whether composed into a role or class), then your above
declaration of FooBar will trigger an exception and force the user to
resolve the conflict.


Well, if we allow FooBar to die, then we do not allow for possible  
disambiguation by a class (which is the only place it matters anyway  
since roles cannot be directly instantiated). I think that not  
keeping the conflict in suspension until the role is composed will  
actually restrict the usefulness of roles. I should be allowed to  
create a role with all sorts of conflicts which I leave for the  
classes to deal with.


Remember that if you create a role with a stub method (method my_stub  
{ ... }) then it acts just like a conflict does in requiring the  
consuming class to implement it.


Stevan



Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Stevan Little


On Oct 28, 2005, at 11:38 AM, Jonathan Scott Duff wrote:

On Fri, Oct 28, 2005 at 04:59:18PM +0200, Yuval Kogman wrote:


If, OTOH we have a diamond inheritence:


You mean composition.  There is no role inheritance  :)


role A { method foo { ... } }
role B does A {};
role C does A {};
class D does A does B { };


I'm assuming you meant

class D does B does C { ... }


I'm not sure we need to resolve the conflict.


It depends on when composition happens. If A is composed immediately
into B and C as soon as the role is processed, then when D is being
composed, all it sees are a foo method from the B role and a foo  
method

from the C role.

If, however, roles aren't composed into other roles but only into
classes, then I think that

class D does B does C { ... }

would be equivalent to

class D does A does B does C { ... }

since the roles B and C would carry the uncomposed A role along with
them.


Personally, I think the later makes the most sense. This fits very  
well with the roles are just containers idea. A role flattens  
method, attributes, *and* subroles too.



If, on the other hand, we have

role X trusts Foo does Foo {
has $:foo;
}



Quoth A12:

It's not clear whether roles should be allowed to grant trust. In
the absence of evidence to the contrary, I'm inclined to say  
not. We
can always relax that later if, after many large, longitudinal,  
double-

blind studies, it turns out to be both safe and effective.

Has that changed?


To quote $Larry[0] A12 should be read for entertainment purposes only

I know, that scares me too ;)


Stevan


Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Jonathan Scott Duff
On Fri, Oct 28, 2005 at 02:29:36PM -0400, Stevan Little wrote:
 I should be allowed to create a role with all sorts of conflicts which
 I leave for the classes to deal with.

Er, why? I've read this sentence several times and I'm really having
trouble grasping why anyone would deliberately create a conflicted role
and want to postpone the conflict resolution until later. It seems to me
that conflicts should be resolved sooner rather than later. Especially
in the light of run-time composition:

role A { method foo { ... } ... }
role B { method foo { ... } ... }
role C does B does A { ... }
my Dog $spot; 
...
$spot does C;

Would you rather wait until perl is actually executing that last line
of code before finding out there's a conflict or would you rather know
there's a conflict at compile-time (when C is immediately composed of
A and B)?

Yes, I realize that Perl6 already has the problem that run-time
composition could cause conflicts, but I want to have a slightly
smaller chance of running into it :)

-Scott
-- 
Jonathan Scott Duff
[EMAIL PROTECTED]


Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Jonathan Scott Duff
On Fri, Oct 28, 2005 at 06:23:28PM +0200, Yuval Kogman wrote:
 On Fri, Oct 28, 2005 at 10:38:31 -0500, Jonathan Scott Duff wrote:
  Er, there is only one $:foo.  X doesn't have any private members, nor
  does Y (because they're roles).  Only C has private members.  So,
  modulo the multiple composition of Foo, I don't think there's a
  conflict.
 
 Really? I didn't know that... In that case roles are broken... They
 will need instance data (that doesn't conflict when it's private) to
 support the methods they give their consumers.
 
 Is there any good reason to not allow roles to introduce member data
 into a class?

Roles can hold instance data that will be composed into a class.  What
I'm saying is that if you have two roles:

role X { has $:foo; }
role Y { has $:foo; }

And a class that's composed of them:

class Xy does X does Y { ... }

That there will not be two slots for $:foo in Xy, but only one.

But, I'm probably wrong about this as the X role may have methods that
use $:foo in one way and the Y role may have methods that use $:foo in
some other, incompatible way, so perhaps there will be a conflict just
as when there are 2 methods of the same name.

-Scott
-- 
Jonathan Scott Duff
[EMAIL PROTECTED]


Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Rob Kinyon
On 10/28/05, Jonathan Scott Duff [EMAIL PROTECTED] wrote:
 Roles can hold instance data that will be composed into a class.  What
 I'm saying is that if you have two roles:

 role X { has $:foo; }
 role Y { has $:foo; }

 And a class that's composed of them:

 class Xy does X does Y { ... }

 That there will not be two slots for $:foo in Xy, but only one.

 But, I'm probably wrong about this as the X role may have methods that
 use $:foo in one way and the Y role may have methods that use $:foo in
 some other, incompatible way, so perhaps there will be a conflict just
 as when there are 2 methods of the same name.

The solution I proposed to Steve is somewhat involved, so let me take a moment.

In my view of objects, there are only behaviors. An attribute is
simply a behavior that will store some value (somehow) when asked and
will return the last value stored (somehow) when asked. The whole
concept of the attribute is to support behaviors that are (ultimately)
used publicly. Hence, from a strict encapsulation POV, the attributes
should be private to the definer.

As such, a role would have private methods that can only be called by
methods defined within that role (stubs aside). Stuff that composes
said role into themselves would only be composing the public API, not
the private API. Those methods that get composed would be able to
access the private methods (attributes or not) that were defined
within the role.

If this solution were to be enacted, then the role wouldn't pollute
the class's attributespace with its attributes and there couldn't be
any conflict between roles or the roles and the classes. This also
extends to attributes and inheritance - the private concept that C++
has. (I don't agree with the protected concept, but private vs. public
is good.)

Doing it any other way leads to the following: if A does rA and B isa
A and B defines an attribute that conflicts with the one provided by
rA, how on earth is that supposed to be detected? Especially given
that the inheritance tree of a class can be modified at runtime.

Rob


Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Stevan Little


On Oct 28, 2005, at 2:54 PM, Jonathan Scott Duff wrote:

On Fri, Oct 28, 2005 at 02:29:36PM -0400, Stevan Little wrote:
I should be allowed to create a role with all sorts of conflicts  
which

I leave for the classes to deal with.


Er, why? I've read this sentence several times and I'm really having
trouble grasping why anyone would deliberately create a conflicted  
role

and want to postpone the conflict resolution until later.


Well, certain classes might want to deal with the conflict in certain  
ways.


role Foo {
method foo { [ 1, 2, 3 ] }
}

role Bar {
method foo { { one = 1, two = 2, three = 3 } }
}

role FooBar {
does Foo; does Bar;
method display_foo {
self.foo.values.join(', ');
}
}

class MyFooArray does FooBar {
foo := Foo::foo;
}

class MyFooHash does FooBar {
foo := Bar::foo;
}

The conflict here basically allows the user of FooBar to determine  
what kind of data structure to use, while also providing basic means  
of displaying the data structure. The example a little contrived, but  
it might be a useful technique in some areas.



It seems to me
that conflicts should be resolved sooner rather than later. Especially
in the light of run-time composition:

role A { method foo { ... } ... }
role B { method foo { ... } ... }
role C does B does A { ... }
my Dog $spot;
...
$spot does C;


Well why should this be any less dangerous that this:

my $spot = (class { does A; does B; }).new();

Which is what it will be desugared into anyway.

It might also be possible for the compiler to catch this kind of  
stuff too.



Would you rather wait until perl is actually executing that last line
of code before finding out there's a conflict or would you rather know
there's a conflict at compile-time (when C is immediately composed of
A and B)?


To be totally honest, I think if you do runtime role composition with  
a role which you know has a conflict (I mean I assume you either  
created that role, or know what it provides before you use it), then  
you deserve all the pain and suffering associated with it.



Yes, I realize that Perl6 already has the problem that run-time
composition could cause conflicts, but I want to have a slightly
smaller chance of running into it :)


Actually, according to the for entertainment purposes only A12, if  
I do this:


$spot does Dog does Cat;

I am really doing this:

$spot = (class { is (class { does Dog; }); does Cat; }).new();

So it won't actually conflict.

Stevan





Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Stevan Little


On Oct 28, 2005, at 3:04 PM, Jonathan Scott Duff wrote:

But, I'm probably wrong about this as the X role may have methods that
use $:foo in one way and the Y role may have methods that use $:foo in
some other, incompatible way, so perhaps there will be a conflict just
as when there are 2 methods of the same name.


Yes, they have to conflict. Attribute conflict rules should be the  
same as method conflict rules.


Stevan


Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Stevan Little


On Oct 28, 2005, at 3:45 PM, Rob Kinyon wrote:

Doing it any other way leads to the following: if A does rA and B isa
A and B defines an attribute that conflicts with the one provided by
rA, how on earth is that supposed to be detected? Especially given
that the inheritance tree of a class can be modified at runtime.


B should not know or care that A does rA, because by the time B gets  
to A, rA has already been consumed by A.


If B does not want it's attributes to conflict,.. make 'em private.  
If rA is concerned that it's attributes will get mussed with, it  
should make 'em private too (which IMO would mean that A gets a new  
private attribute, not that it is privatet to the role).


Your method (as we have discussed in the past) means that Roles now  
have instance specific data, which needs to be stored somewhere,  
somehow (not too difficult). And our class now needs to keep  
information about the roles it composed around so that it can  
dispatch to methods appropriately (also not too bad). This then means  
that the method dispatcher, when it cannot find a private method  
locally, needs to check all the roles which were composed into the  
class to find the correct private method and then call that method (I  
assuming no method conflicts here, but they can (and will) happen).  
The method then needs to be able to find and extract the role  
specific private instance data (this action itself requires some  
complex access control checks), and then do something with it.


Like I said, this is assuming we have no conflicts, because the  
dispatcher will have a hard time determining which role specific  
private method named :foo you mean in the context this is all  
happening in. And if we check for conflicts up front, we start to run  
into the same issues that we did before.


One possible solution might be to only allow methods defined within  
the role to access the private role methods. But then what happens if  
that method is in conflict. Here is an example:


role Foo {
has $:bar; # this is role private data
method :get_bar { $:bar } # a role private method

method gimme_bar { self.:get_bar() } # the public face to the  
private role data

}

class Blah does Foo {
method gimme_bar { ... }
}

At this point :get_bar and $:bar are totally inaccessible.

IMO, roles should be just containers, and they should hand over  
everything they have to the class they are composed into. I also  
think Subclasses should not care what roles their superclasses  
consumed, that is personal information for the class only to know.


Stevan




Re: Role Method Conflicts and Disambiguation

2005-10-28 Thread Jonathan Lang
To me, the distinguishing feature between the role and class concepts
has always been that roles lack internal structure: you don't have to
worry about any hierarchies of what went into creating the role; you
just have to pay attention to what attributes and methods it will add
to whatever class you compose it into.

If A and B have method foo, and AB does both A and B, then AB should
have one of: A's version, B's version, its own version, a virtual
pass the buck version, or no version at all; it shouldn't have a
hierarchy of versions to pick from.  If you compose AB into a class,
but you don't want the version of foo that it brings to the table (or
if AB went with the pass the buck option), then you should either
override it with your own version or explicitly bring in another role
that has the version that you want - be it A, B, or Q.  If you want to
deal with hierarchies of methods, deal with classes instead of roles.

--
Jonathan Dataweaver Lang


Re: Role Method Conflicts and Disambiguation (Theory-theoretic take)

2005-10-28 Thread Luke Palmer
Here's how I see roles.  This is just an attempt to formalize our
concepts so that the answer becomes an obvious truth rather than a
decision.

A role is an interface with some default implementations.  Here's an example:

role Foo {
# anything that conforms to Foo must provide a foo() method
# if one is not provided, this body is used instead
method foo () { say hi }

# anything that conforms to Foo must provide a bar() method
# if one is not provided, then there is an error
method bar () {...}

# anything that conforms to Foo must provide a baz() method
# if one is not provided, then an instance variable is used instead
has $.baz;
}

role Bar {
# anything that conforms to Bar must provide a bar() method
method bar() {...}
}

# this is a conditional: anything that conforms to FooBar also
# conforms to Foo and Bar
role FooBar {
does Foo;
does Bar;

# the requirement for the implementation of a bar() method is
# carried over[1]
}

This is a sort of suspension.  If you ignore the roles Foo and Bar,
you have simply a role FooBar that has three requirements: foo(),
bar(), and baz(), where foo() and baz() have defaults.  When you
compose this into an empty class, you will get not a conflict but a
missing method error.  bar() was not implemented.

Now, let's say that bar() was given a default implementation in Foo. 
Then FooBar would be a fully-defined role with no requirements.

Let's say that bar() was given a default implementation in both Foo
and Bar.  That's a conflict.  But let's follow suit and pretend that
Foo and Bar didn't exist.  If you try to compose in FooBar, you will
get an ambiguity, which can be resolved by defining your own bar(). 
So clearly, FooBar simply has a required foo() again.

To summarize, as we'll use this later:

Foo:foo() default, bar() default, baz() default
Bar:bar() default
FooBar: bar() required

So then we take that, and say that we can give a default
implementation for this now-required method.  FooBar may disambiguate.

Moving on.

role Baz {
does Bar;
}

By my free-derivation (or composition in this case, I guess)
principle, Baz is now equivalent to Foo.  If you think of them as
interfaces, it makes perfect sense.  Baz provides no additional
implementations, nor imposes any additional requirements, and thus you
must do precisely the same things to conform to Baz as to Foo.

Baz: bar() default

Now:

class MyClass does FooBar does Baz { }

Here's where the theory proposal comes in, yet again.  The definition
of a class is just the definition of a role together with a
(syntactically impossible) declaration of a concrete type.   Creating
the class is erroneous if the role is not fully-defined.  So let's
just look at the role half:

role MyClass {
does FooBar;
does Baz;
}

Now we ignore the inner workings of FooBar and Baz.  This is a good
idea, as it lets us refactor freely, as long as it looks the same from
the outside.  Recall that we had:

Baz: bar() default
FooBar:  bar() required

So clearly Baz fulfills FooBar's requirements, and MyClass is a
fully-defined role.

Okay, how did that happen?  What was the formality that we actually used?

It was the fact that at each stage of the game, we summarized the
defaults and requirements for each role, ignoring the internal makeup
(i.e., what roles were composed into it, etc.).

And it sounds correct to me.

Luke

[1] Perhaps we even require declaration.  We probably shouldn't, in
the name of keeping Perl Perl.  Any good documentation system ought to
catalog all the dependencies.


Re: Role Method Conflicts and Disambiguation (Theory-theoretic take)

2005-10-28 Thread Stuart Cook
On 29/10/05, Luke Palmer [EMAIL PROTECTED] wrote:
 Moving on.

 role Baz {
 does Bar;
 }

 By my free-derivation (or composition in this case, I guess)
 principle, Baz is now equivalent to Foo.  If you think of them as
 interfaces, it makes perfect sense.  Baz provides no additional
 implementations, nor imposes any additional requirements, and thus you
 must do precisely the same things to conform to Baz as to Foo.

 Baz: bar() default

You meant to write 'equivalent to Bar', not Foo, right?


Stuart


Re: Role Method Conflicts and Disambiguation (Theory-theoretic take)

2005-10-28 Thread Jonathan Lang
On 10/28/05, Luke Palmer [EMAIL PROTECTED] wrote:
 Here's how I see roles.  This is just an attempt to formalize our
 concepts so that the answer becomes an obvious truth rather than a
 decision.

 A role is an interface with some default implementations.

-snip-

 Now we ignore the inner workings of FooBar and Baz.  This is a good
 idea, as it lets us refactor freely, as long as it looks the same from
 the outside.

I would say that this isn't just a good idea; it's at the core of what
distinguishes composition from inheritance.  With classes and
inheritance, you keep all of the baggage that accumulates at each
step, on the off-chance that some as-yet unknown descendant might need
it.  With composition the only baggage that a role keeps is the
baggage that is directly relevant to itself.  Whatever gets tossed
aside can be composed in separately later on if it's needed.

 Recall that we had:

 Baz: bar() default
 FooBar:  bar() required

 So clearly Baz fulfills FooBar's requirements, and MyClass is a
 fully-defined role.

 Okay, how did that happen?  What was the formality that we actually used?

 It was the fact that at each stage of the game, we summarized the
 defaults and requirements for each role, ignoring the internal makeup
 (i.e., what roles were composed into it, etc.).

 And it sounds correct to me.

Me, too.

--
Jonathan Dataweaver Lang


Re: Role Method Conflicts and Disambiguation (Theory-theoretic take)

2005-10-28 Thread Rob Kinyon
On 10/28/05, Luke Palmer [EMAIL PROTECTED] wrote:
[snip]
 It was the fact that at each stage of the game, we summarized the
 defaults and requirements for each role, ignoring the internal makeup
 (i.e., what roles were composed into it, etc.).

So, in theory, one should be able to ask any given role What do you
provide? as well as What do you require?. (I'm not saying that the
syntax should be available, but that the information to answer those
questions should be easily calculable.)

One concern I have is that I would like to believe that a role is a
group of related behaviors that provides a functionality. So, if Foo
does roleA and I as the user of Foo asks Do you do roleA? and it
replies Yes, then I can make some assumptions about Foo's
functionality. Otherwise, this devolves into interfaces. Interfaces
suck, especially given as they're limited to naming.

Now, if we were to say that all roles, by default, provide
multimethods, then conflicts only occur for methods that have
identical dispatching semantics. At that point, it's truly a conflict
and would need to be resolved by the composer (whether that's a role
or a class).

Now, it's obvious why a class would have to resolve that conflict. I
would say that a role would have to resolve the conflict is that a
role should present a consistent API to the rest of the world. In
other words, I want to be able to depend on the fact that classA does
roleAB means something in terms of the functionality that classA
provides to me. I don't want it to be a glorified can() check. That
does no-one any good.

Rob


Re: Role Method Conflicts and Disambiguation (Theory-theoretic take)

2005-10-28 Thread Luke Palmer
On 10/28/05, Rob Kinyon [EMAIL PROTECTED] wrote:
 Now, it's obvious why a class would have to resolve that conflict. I
 would say that a role would have to resolve the conflict is that a
 role should present a consistent API to the rest of the world. In
 other words, I want to be able to depend on the fact that classA does
 roleAB means something in terms of the functionality that classA
 provides to me. I don't want it to be a glorified can() check. That
 does no-one any good.

Most certainly.  Implicit in a role or a theory is its algebra (though
we've talked about QuickCheckish ways to make it explicit).   For
instance, technically the VectorSpace theory only requires you to
define identity, addition, and scalar multiplication.  However, in
order to honestly do VectorSpace, addition has to be commutative,
which is something that the compiler usually is not able to check.

And that's why you have to explicitly say that your class does the
role, rather than it just inferring that from the methods you provide.
 You may have named your methods the same, but there's no guarantee
that you obey the role's algebra.  By saying that your class does
the role, you are promising that these methods do indeed obey the
necessary algebra.

So in a way, it's a kind of glorified can().  But in another way, it
does guarante certain kinds of behavior from the implementing objects.
 If you do a role and override a method that violates what the role is
supposed to guarantee, then you don't really do that role, even though
you do as far as the compiler knows.   It's a conceptual contract, not
a computationally rigorous one.

On the computational level, a role is little more than an interface
with defaults.

Luke


Re: Role Method Conflicts and Disambiguation (Theory-theoretic take)

2005-10-28 Thread Stevan Little

Luke,

On Oct 28, 2005, at 9:44 PM, Luke Palmer wrote:

It was the fact that at each stage of the game, we summarized the
defaults and requirements for each role, ignoring the internal makeup
(i.e., what roles were composed into it, etc.).


This then imposes somewhat of an ordering with role composition. The  
role tree will need to be traversed breadth first, and conflicts/ 
requirements resolved on a level by level basis.



And it sounds correct to me.


It sounds correct to me as well (in theory,.. get it ,... in  
theory :P).


However, I do worry about how it will work out in practice. Part of  
the goal of roles (and I have been preaching this one since the  
hackathon) is that they are easier to use than multiple inheritance,  
have fewer headaches than mix-ins and are more useful than  
interfaces. Imposing ordering as described above may make things  
easier, or it may make things harder, only time and experience will  
tell. I am going to give this some more thought over the weekend, and  
see what I come up with.


Stevan


Role Method Conflicts and Disambiguation

2005-10-27 Thread Stevan Little

Hello all,

I have a question about method conflict resolution works for roles,  
and I cannot seem to find this in any of the Apoc/Syn documents.


Here is the basic issue:

role Foo {
method foo { ... }
method bar { ... }  # we will use this later :)
}

role Bar {
method foo { ... }
}

role FooBar {
does Foo;
does Bar;
}

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?


role FooBar {
does Foo;
does Bar;
method foo { ... }
}

Now, on the surface this seems obvious, of course the FooBar role  
should be able to disambiguate. However, when we expand the example  
other issues show up.


role Baz {
does Foo;
}

class MyClass2 does FooBar does Baz {}  # Will this die?

Now, since MyClass2 actually does Foo twice, does that mean bar  
creates a conflcit? Since bar would be found through FooBar and Baz.  
I would think the answer here would be no, and that we would build  
some kind of unique list of roles so as to avoid repeated consumption  
like this.


But thats not all, we have a potential problem with foo again. Baz  
will provide foo from Foo, but FooBar will provide it's own foo  
(which we used to disambiguate). So our disambiguation is not  
ambiguated again.


/ Possible Solutions /

A (deceptively) simple solution to this is that MyClass2 needs to  
disambiguate. But this means that our roles are not really black  
boxes anymore. In order to properly disambiguate this we need to know  
where all the foo methods are coming from (Foo, Bar and FooBar), and  
potentially what is inside these foo methods (especially in the case  
of FooBar since it is attempting to disambiguate, it's behavior could  
be very specific). It probably would also become important to know  
what other methods foo interacts with since we potentially have 3  
different expected versions of foo.


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.


Another simple (but maybe slightly unintuitive) solution would be to  
not allow roles to disambiguate at all.


(Quick side note: Doing this means that roles like FooBar (which  
carry with them a suspended conflict) would be restricted in what  
types of behaviors they can provide. Basically they would only be  
able to provide new behaviors which are unrelated to those provided  
by Foo and Bar. If it were to try to use methods from Foo or Bar, it  
would really end up needing to disambiguate.)


This actually makes MyClass2 somewhat simpler now, since it only need  
to disambiguate between foo from Foo, and foo from Bar. Of course  
this is only marginally better, since you would still need to look  
inside all the methods of Foo, Bar, FooBar and Baz to see how foo is  
being used so you could disambiguate properly.


...

So what do you all think??

Stevan