TSa wrote:
Secondly I figure you are operating on the extension set a role
defines. That is union produces a supertype aka the larger set
of instances. This is in accordance to the usual type theory
approach. Note that Jonathan operates on the intension set of roles
that is union produces a subtype.

Assuming that I understand the terminology correctly, I'll go further
and say that one of the big differences between roles and subtypes
(using the terms in their perl 6 contexts) is that roles conceptually
operate on intension sets - everything about them is defined in terms
of their set of capabilities - while subtypes (i.e., objects with
"where" clauses) operate on extension sets - they're defined in terms
of the valid set of instances.

Incidently, I'm using terms like "supertype", "subtype", "superrole",
"subrole", etc. strictly due to a lack of a better alternative.
"Supertyping" only leads to a larger set of instances because a
parameter that asks for the supertype is willing to accept a subtype
in its stead.

> Things work a little differently for required methods.  When a
> superrole requires a method be implemented, we (the language
> designers) have a choise 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 can see no brittleness. The role that is supertyped is already
fully defined when the superrole is about to be created. Thus it can
be checked if required but unimplemented methods---that is ones with
a {...} body---are present. These should be rejected on the rational
that the pre-existing code can't retroactively be made to implement
the method.

That's the brittleness: the set of methods that you are permitted to
define in the superrole is restricted to the set of methods in the
role being generalized.  Since Num doesn't include methods re or im,
an attempt to include either method in a Complex superrole would be an
error according to this approach, or it would involve changing Num to
include methods re and im in the alternative approach.

The write-up that I saw in the original message seems to carry the
implication of the alternative approach (of back-editing the new
methods into the subrole).  Note that if you go this route, you really
should allow yourself to define multiple versions of the new method:
one for the superrole, and one for each of the subroles used to define
it.  I'd rather not go this route, though.

>  It means that
> when you are implementing a role in a class, all you have to look at
> for what you need to do is the role and the roles that it includes;
> you don't need to scan the entire source for superroles which
> encompass the one you are implementing.  That is the user-friendly way
> to put it, but there is an analogous argument for independent
> modularity (you don't want the definition of a new superrole to
> invalidate objects that already exist).

Well spoken.

And agreed.

> Things get a little tricky when you think about "does" and "superdoes"
> together:
>    role Foo does Bar superdoes Baz {...}
> What does that mean?  Okay, Foo is a subset of Bar, and a superset of
> Baz.  Already by simply declaring this we have mandated that "Baz does
> Bar".  If Baz doesn't already conform to the interface of Bar, Foo
> better fill in the gaps for it.

Sorry, but no.  If Baz doesn't already conform to the interface of
Bar, you're dead in the water.  "Filling in the gaps" amounts to
changing Baz, which is not in Foo's purview.

In the thread 'signature subtyping and role merging' I have argued
the need of merging method signatures that come in from different
superroles. This is less of a problem when creating superroles because
one can drop the method from the interface and maintain the subtyping
relation. So filling in the gaps is a hard task in general. I mean
in your example Foo has to define all methods required by Bar so that
Baz has at least the default provided by Foo. The gap between Baz and
Bar might also contain unresolvable name clashes that are of course
no problem as long as Bar and Baz are unrelated.

This is why I think that having both "does" and "done_by" declarations
in a role definition is a mistake: the whole thing becomes a cryptic
mess far too quickly.

A thing that is still unclear to me is how the issue of the supertype
intercepting lvalue uses of its methods is resolved. Preferably in a
declarative style. I mean a simple 'is rw' trait will hardly do because
you have to return a complete object of which only an attribute is
written to. The former subtype value has to be made available for the
lvalue method for constructing the new supertype lvalue.

Look at it according to the normal flow: if you subtype a role with
read/write capabilities, the new role cannot have fewer rw
capabilities than the role that it's composing has.  Reversing this,
if a role does not have a particular rw capability, then a superrole
cannot add it.  This is a variation on the "adding methods to the
superrole" debate.

Mind you, once you've defined a supertype, you can freely create new
subtypes of it, and you can add whatever features you want to those
new subtypes, be they lvalue access, new methods, or anything else.
IMHO, the correct way to create an unordered Complex role from a Num
role is to use supertyping to remove the ordering capabilities from
Num, and then use subtyping to add "imaginary component" capabilities
to that.  Yes, this means that a simple partial ordering check between
Complex and Num will result in a "no relation" result; but that's a
shortcoming of the type-checking system, not the type definition

Jonathan "Dataweaver" Lang

Reply via email to