Luke Palmer wrote:
When you say:

   role Foo superdoes Bar superdoes Baz {...}

You are saying Foo = Bar (+) Baz (+) ...;  # union of Bar, Baz, and
the following spec

For the record, I think that "superdoes" should be spelled "done_by".

It may seem like that should be Foo = (Bar (+) Baz) (*) ...;  (indeed,
I thought that for a while and then corrected myself).  But if
anything that is a Bar is a Foo, anything that is a Baz is a Foo, and
some other stuff is also a Foo (this being the important case), then
that should clearly be a union.

Note that in your usage of the set operations, "Bar (+) Baz" requires
"Bar.^methods (*) Baz.^methods" and "Bar (*) Baz" requires
"Bar.^methods (+) Baz.^methods".  This means that the spec that
follows would act to further limit the methods that end up in Foo,
such that only methods that appear in Bar, Baz, _and_ the spec would
end up in Foo.  (As a secondary issue, your definition of "Bar (+)
Baz" strikes me as counterintuitive; but maybe that's because I tend
to view roles as sets of methods.)

Things work a little differently for required methods.  When a
superrole requires a method be implemented, we (the language
designers) have a choice to make: it is illegal if the superrole
requires a method that the subroles don't implement or don't
themselves require, or it simply adds the new method to the required
list of the subroles which don't implement it.  I'm inclined to say
the former, even though it seems a little more brittle.

I agree with your inclination; but bear in mind that this would make
it illegal to define Complex as a superrole of Num, since Complex has
methods that Num doesn't have.  Also bear in mind that if Complex is a
superrole of Num, a parameter that asks for a Num should by all rights
reject a Complex that's handed to it.

I agree with the idea of being able to define superroles (for lack of
a better name); my problems lie entirely with the proposed
implementation of the concept.  I'll reiterate my alternative:

When using set operations with roles, treat the roles as sets of
methods.  Each set operation defines an anonymous role with the
resulting set of methods; as with any other anonymous thing, it can be
bound to a name.  In addition, a few of the set operations establish
.does() relationships between the new role and the roles used to
create it:

  role C ::= A (+) B # C.does(A) and C.does(B)
  role D::= A (*) B # A.does(D) and B.does(D)
  role E ::= A (-) B # A.does(E)

and so on.  In particular, these lines would be equivalent to

  role C does A does B {}
  role D done_by A done_by B {}
  role E done_by A except B {}

...with the added benefit that you don't have any confusion as to how
"does", "done_by", "except", etc. interact with each other or with the
new spec.  Further, grouping of set operations makes it easy to define
"staged composition":

  (A (+) B) (*) C

would mean "compose an anonymous role as the union of A and B, and
then compose an anonymous role as the intersection of that and C".
Among other things, this would allow method definitions in C to
override those of the anonymous union.

Jonathan "Dataweaver" Lang

Reply via email to