TSa wrote:
Jonathan Lang wrote:
>    role R3 does A & B { ... }
>    R3.does(A) # false: R3 can't neccessarily do everything that A can.
>    A.does(R3) # false: A can't neccessarily do everything that R3 can.

That last one should be true. Role R3 contains the things that A and B
have in common. Hence each of them has everything that R3 has.

The '...' above isn't the yadda-yadda operator; it's a standin for
whatever gets declared in R3.  Which leads directly to...

> And because you have the ability to add methods to R3 that aren't in A
> or B, you can't make use of the fact that A & B is a subset of A for
> type-checking purposes.

The really funny thing is what can be written into the body of role R3.
Should it be forbidden to introduce new methods? Or should new methods
automatically enter into A and B? The latter would be more useful but
then roles become somewhat open like classes because code that did not
typecheck before the superrole creation suddenly typechecks after it.
Or if the role R3 adds a yada method that propagates down the
composition chains, classes might retroactively fail to compile!

In short, R3 isn't neccessarily a subset of A; it's a superset of A &
B.  In a partial ordering graph, there's no reliable ordering between
R3 and A.

The standard syntax for creating roles can't reliably produce a subset
of an existing role, because it always allows you to add to it.
That's why I suggested the idea of binding a role name to a set
operation: with 'role Foo ::= A & B', Foo is a subset of A, because
Foo is 'A & B', and 'A & B' is a subset of A.  In addition, this
syntax doesn't rely on the 'does' keyword, so there's no implication
that the LHS must be a semantic superset of the RHS.

Also, there's no danger of overriding a yadda-yadda in A: the only way
to bring your own definitions into Foo would be to use an anonymous
role as one of the roles on the RHS: either that role gets brought in
via '&' (in which case only those methods that are common to A and the
anonymous role will end up in Foo, and thus will be overridden by A),
or it gets brought in via '|' (in which case Foo is no longer a subset
of A, and 'A.does(Foo)' will be false).  In fact,

   role Foo does A does B { ... }

can be thought of as being semantically equivalent to

   role Foo ::= (A | B) | role { ... }

The only problem that might crop up is the use of 'A | B' in
signatures to mean 'can match any of A, B' - that is: in signatures,
'A | B' refers to the junctive operator; while in the above proposal,
'A | B' refers to the set union operator.  Different semantics.

Jonathan "Dataweaver" Lang

Reply via email to