Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

set operations for roles

5 views
Skip to first unread message

Jonathan Lang

unread,
Oct 19, 2006, 6:39:38 PM10/19/06
to perl6language
In "class interface of roles", Dr.Ruud wrote:
> And I was on the line of:
>
> role R does A | B | C { ... } # unordered composition
> $x does ( A, B, C ) ; # ordered composition
> $y does A | B | C ; # unordered composition
>
> but I would like early and late binding to be explicit.
> Maybe the coder will use () around the run-time ones.

Note that compile-time "is" and "does" declarations can be applied
before the curly braces or inside them; if applied inside, each one is
treated as a separate statement:

class Foo is A is B does R { ... }

class Foo {
is A;
is B;
does R;
...
}

Unless you put a restriction that the body can have no more than one
"does" statement, I would expect the symmetry between these two cases
to be maintained:

role R {
does A;
does B;
...
}

role R does A does B { ... }

And since one of the basic principles of multiple role composition is
that ordered composition should not be encouraged, this syntax should
represent unordered composition if it remains at all (and I think it
should). And if unordered composition can be done this way at
compile-time, it ought to be doable in an analogous way at runtime as
well.

That said, TIMTOWTDI. I could see "does A | B | C" being used as a
valid alternative to "does A does B does C" on the theory that '|' is
being used like a union operator and 'A', 'B', and 'C' can be viewed
as sets of methods.

One thing which should be considered when deciding whether or not to
permit this sort of syntax is that the availability of a union-ish
operator implies the availability of other set-like operators, such as
"does A & B" or "does A - B". The problem with these latter
definitions is that, conceptually, the new role is not a superset of
either of the old ones:

role R1 does A { ... }
R1.does(A) # true: R1 can do everything that A can.
A.does(R1) # false: A can't neccessarily do everything that R1 can.

role R2 does A | B { ... }
R2.does(A) # true: R2 can do everything that A can.
A.does(R2) # false: A can't neccessarily do everything that R2 can.

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.

This dissonance comes from the fact that "does" is being used in two
different ways here: as an instruction to help define a class or role
based off of another role or roles, and as a test of whether something
is a semantic superset of a role. As long as the former only adds to
or changes the roles that it composes, the two concepts are in synch;
but once you allow subsets of roles to be composed, the symmetry
breaks.

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.

--

Hmm... how about allowing something analogous to binding as the basis
for set-like role composition:

role Foo ::= A; # Foo.does(A) and A.does(Foo)
role Foo ::= A | B; # Foo.does(A) and Foo.does(B)
role Foo ::= A & B; # A.does(Foo) and B.does(Foo)
role Foo ::= A - B; # A.does(Foo)

The first case would merely make Foo synonymous with A; nothing special here.

The second case would be equivalent to "role Foo does A does B { }".

The third case would create a new role that includes only those
methods that both A and B have; in addition, it would modify the
definitions of both A and B so that they compose Foo.

The fourth case would include those methods that are in A but not in
B, and would modify the definition of A so that it composes Foo.

These modifications to A and B won't change their existing behavior;
they'll merely add to the range of types that A and B will match.

In all of these cases, you don't get to add functionality to the new
role. If A and B have methods that conflict, both A | B and A & B
will include an undefined method instead. If you want to add
functionality, compose Foo into something else and add the
functionality there.

One could try to extend this notion: "A | B" creates an anonymous role
that composes A and B; "A & B" creates an anonymous role that both A
and B compose (for type-checking purposes only); "A - B" creates an
anonymous role that A composes (again, for type-checking purposes
only). These expressions can be used in "does", or they can be bound
to a name using '::=' (or ':=' at runtime). If parentheses get used,
you could have something akin to ordered composition, with the
innermost set operators being evaluated first: so "(A | B) | C" would
compose an anonymous role that merges A and B, and would then compose
C into the result - meaning that if A and B have conflicts, C can
resolve them. So strictly ordered composition could be done as:

role Foo does (((A) | B) | C) { ... }

making it visually explicit as to what gets done when. This would
require that '&' and '|' (and possibly '-') be list-associative when
dealing with roles. I suppose that the comma could be overridden so
that 'A, B' is synonymous with '(A) | B' when A and B are roles; but
then you'd lose the ability to construct lists of roles. And I
suspect that the above Huffman encoding is more appropriate, anyway.

If you want to define a subset of an existing role as a new role, you
could say something like:

role Comparator := Num & role {
method infix:< <= > { ... }
...
}

...and then anything that asks for a Comparator would accept a Num.
Of course, it wouldn't accept a Str; you'd have to say "Num & Str &
role { ... }" for that.

--
Jonathan "Dataweaver" Lang

TSa

unread,
Oct 20, 2006, 3:33:57 AM10/20/06
to perl6language
HaloO,

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.


> 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!

Regards, TSa.
--

Jonathan Lang

unread,
Oct 20, 2006, 5:21:48 AM10/20/06
to perl6language
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

TSa

unread,
Oct 20, 2006, 8:01:17 AM10/20/06
to perl6language
HaloO,

Jonathan Lang wrote:
> 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.

Yes, but I was conjecturing that the additions to A&B are pushed
down to A and B such that their intension sets remain strict supersets
of A&B.


> 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.

In fact if we decide to specify a role combination syntax then it
should be the same everywhere. That means in a signature A|B would
require a more specific type and pure A or B wouldn't be admissible.
To get the old meaning of | you have to write A&B or perhaps the
juxtaposition which currently means what A|B should mean. Alternatively
the meaning of the role combination A&B could be defined to mean the
union and A|B the intersection.


Regards, TSa.
--

TSa

unread,
Oct 20, 2006, 9:48:45 AM10/20/06
to perl6language
HaloO,

I wrote:
> In fact if we decide to specify a role combination syntax then it
> should be the same everywhere. That means in a signature A|B would
> require a more specific type and pure A or B wouldn't be admissible.
> To get the old meaning of | you have to write A&B or perhaps the
> juxtaposition which currently means what A|B should mean. Alternatively
> the meaning of the role combination A&B could be defined to mean the
> union and A|B the intersection.

Here is yet another idea to go with the two lattice operations:

/\ meet also: infimum, intersection, glb (greatest lower bound)
\/ join also: supremum, union, lub (least upper bound)

These have nice graphical mnemonics

meet={x}
/\
/ \
/ \
A={a,x} B={b,x}
\ /
\ /
\/
join={a,b,x}

and also read nice as english words:

role J joins A, B, C; # same as role J does A \/ B \/ C
role M meets A, B, C; # same as role M does A /\ B /\ C

Comments?
--

TSa

unread,
Oct 20, 2006, 11:11:10 AM10/20/06
to perl6language
HaloO,

I wrote:
> Yes, but I was conjecturing that the additions to A&B are pushed
> down to A and B such that their intension sets remain strict supersets
> of A&B.

Think of the Complex example that might read

role Complex does Num & !Comparable
{
method im { return 0; }
method re { return self as Num } # a no-op for Num
}
class Complex does Complex
{
has $.re; # accessor overwrites role method
has $.im; # accessor overwrites role method
}

Apart from the fact that the role and the class compete for the
same name slot this looks like what you need to make Num applicable
wherever a Complex is expected:

module A
{
use Complex;
Num $a;
say $a.im; # statically type correct, prints 0
}
module B
{
Num $b;
say $b.im; # syntactically admissible, but produces runtime error
}

Actually the 'self as Num' should return the self type ::?CLASS to
preserve as much type information as possible. Hmm, could we get
the keyword Self for that?


Have a nice weekend, TSa.
--

Jonathan Lang

unread,
Oct 20, 2006, 11:57:11 AM10/20/06
to perl6language
TSa wrote:
> Jonathan Lang wrote:
> > 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.
>
> Yes, but I was conjecturing that the additions to A&B are pushed
> down to A and B such that their intension sets remain strict supersets
> of A&B.

I know; but as you pointed out, a single undefined method brought in
this way would break every existing class that composes A or B.

Besides, there's the principle of the matter: creating a new role
should not change the behavior of existing roles. Admittedly, I'm
bending that rule when I suggest that A should get A&B added to its
list of roles when A&B is created; but I'm not breaking it, because
A&B won't have anything in it that A doesn't already have, and A will
uniformly override any behaviors that A&B might provide. The _only_
thing that this change does is to let A match A&B for type-checking
purposes. But letting R3 backend new methods into A _does_ change A's
behavior: it now has methods that it didn't used to have. This can
lead to a more subtle version of the yadda-yadda problem that you
pointed out: if someone has a routine that depends on a failure
occurring if A.m is called, then the routine will stop working as
expected if you backend .m into A via R3.

> > 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.
>
> In fact if we decide to specify a role combination syntax then it
> should be the same everywhere.

Agreed - but we're not talking about role combination syntax in both
places. In signatures, we're talking about a conjunction of two
distinct roles, which is not the same as any sort of combined role
(union or intersection). In particular, the conjunction treats each
role as an atomic unit, while unions and intersections deal with their
elements.

--
Jonathan "Dataweaver" Lang

Jonathan Lang

unread,
Oct 20, 2006, 12:10:12 PM10/20/06
to perl6language
TSa wrote:
> Here is yet another idea to go with the two lattice operations:
>
> /\ meet also: infimum, intersection, glb (greatest lower bound)
> \/ join also: supremum, union, lub (least upper bound)

I have to admit: if it turns out that '&' and '|' can't be used for
'intersection' and 'union', '/\' and '\/' wouldn't be the worst
choices to replace them. But I'd like to verify that we can't use
what we currently have first, before we go changing things.

> and also read nice as english words:
>
> role J joins A, B, C; # same as role J does A \/ B \/ C
> role M meets A, B, C; # same as role M does A /\ B /\ C

I'm less enthusiastic about this, though: perl already uses 'join' for
list concatenation.

--
Jonathan "Dataweaver" Lang

Larry Wall

unread,
Oct 20, 2006, 3:07:53 PM10/20/06
to perl6language
On Fri, Oct 20, 2006 at 09:10:12AM -0700, Jonathan Lang wrote:
: TSa wrote:
: >Here is yet another idea to go with the two lattice operations:
: >
: > /\ meet also: infimum, intersection, glb (greatest lower bound)
: > \/ join also: supremum, union, lub (least upper bound)
:
: I have to admit: if it turns out that '&' and '|' can't be used for
: 'intersection' and 'union', '/\' and '\/' wouldn't be the worst
: choices to replace them. But I'd like to verify that we can't use
: what we currently have first, before we go changing things.

I think we should reserve | and & for matching predicates (read: signatures
and where clauses) rather than type construction. We have to remember
that type theory is completely inside-out to the way most Perl programmers
think. Type theory is all about Platonic objects and how you go about
constructing such abstractions in the abstract. Most people don't want to
think on that level, and are quite willing to delegate the high-powered
abstractions to someone else. Therefore I'd like these to be illegal:

subset X of Y | Z;
subset X of Y & Z;
subset X of Y ^ Z;

and need to be written more like:

subset X of Any where Y | Z;
subset X of Any where Y & Z;
subset X of Any where Y ^ Z;

I now think it's a bad idea to overload | or & to do type construction,
especially since the tendency is to define them backwards from the
operational viewpoint that most Perl programmers will take.

: >and also read nice as english words:


: >
: > role J joins A, B, C; # same as role J does A \/ B \/ C
: > role M meets A, B, C; # same as role M does A /\ B /\ C
:
: I'm less enthusiastic about this, though: perl already uses 'join' for
: list concatenation.

We can negotiate the color of the bikeshed over time. I don't
personally have a problem with meets and joins, and while you might
think that \/ makes it impossible to write [\/] to get a reducing
divide, that's not an operator you'd likely want anyway. But one of
the basic underlying principles of Perl 6 is that we don't have to
overload different operators in a confusing way anymore. \/ should
probably be the ASCII workaround for ∨ while /\ is the ASCII for ∧.
And at one point @Larry reserved all the parenthesized operators for
the ASCII workarounds for set operators.

Anyway, I think the type constructors need to avoid overloading the
logic operators. Perl 6 is an operator-rich language because that
contributes to long-term clarity despite the short-term confusion.

Larry

Jonathan Lang

unread,
Oct 20, 2006, 6:28:27 PM10/20/06
to perl6language
Larry Wall wrote:
> Anyway, I think the type constructors need to avoid overloading the
> logic operators. Perl 6 is an operator-rich language because that
> contributes to long-term clarity despite the short-term confusion.

OK. My main dog in this race is the idea of defining new roles
through the concepts of the intersection or difference between
existing roles (even the union was thrown in there mainly for the sake
of completion), with the consequent extension of the type system in
the opposite direction from the usual one (toward the more general);
the exact syntax used for this is less of an issue, as long as it is
straightforward and simple. Given that the set analogy is exactly
what I'm using, I'd be fine using the Set operators (presumably '∪'
and '∩') and their ASCII workarounds ('(|)' and '(&)'?) instead of '|'
and '&'. Presumably, '-' is still the "difference of Sets" operator.

And yes, this "roles as sets" paradigm would presumably mean that you
could examine roles using '⊂', '⊃', '∈', and so on. Given the
semantic aspect of roles, I don't think that I'd go along with saying
that 'A ⊃ B' is equivalent to 'A.does(B)' - although I _would_ agree
that if 'A.does(B)' then 'A ⊃ B'. Rather, I'd think of 'A ⊃ B' as
being the means that one would use for duck-typing, if one really
wanted to (presuming that one can mess with how perl 6 does
type-checking).

Likewise, 'm ∈ R' will match if 'R.can(m)'; but the definition of
'element' might be broader than just methods.

--
Jonathan "Dataweaver" Lang

TSa

unread,
Oct 23, 2006, 7:10:47 AM10/23/06
to perl6language
HaloO,

Larry Wall wrote:
> I now think it's a bad idea to overload | or & to do type construction,

Is it then a god idea to overload the set operations? At least the
type constructions are set theoretic on the intension set of the
roles.


> especially since the tendency is to define them backwards from the
> operational viewpoint that most Perl programmers will take.

Can you give an example how these directions collide? Is it the
fact that A(|)B produces a subtype of A and B, and that A(&)B
produces a supertype? I can imagine that 'does A&B' could be
read as doing both interfaces.


BTW, what is set complement? Is it (!)?


Regards, TSa.
--

TSa

unread,
Oct 23, 2006, 7:39:53 AM10/23/06
to perl6language
HaloO,

Jonathan Lang wrote:
> OK. My main dog in this race is the idea of defining new roles
> through the concepts of the intersection or difference between
> existing roles (even the union was thrown in there mainly for the sake
> of completion), with the consequent extension of the type system in
> the opposite direction from the usual one (toward the more general);

I strongly agree. Having a language that allows supertying has novelty.
But I think that union is not there for completion but as integral part
when it comes to defining a type lattice which I still believe is the
most practical approach to typing. This includes computed types, that
is "artificial" nodes in the lattice. These intermediate types are
usually produced during type checking and automatic program reasoning.

Think e.g. of the type of an Array:

my @array = (0,1,2); # Array of Int
@array[3] = "three"; # Array of Int(&)Str

This Int(&)Str type might actually be Item. The flattened |@array
has type Seq[Int,Int,Int,Str] but the unflattend array should say
something that is applicable to all its contents. The array might
actually maintain this content type at runtime.


> And yes, this "roles as sets" paradigm would presumably mean that you
> could examine roles using '⊂', '⊃', '∈', and so on.

BTW, are the ASCII equivalents spelled (<), (>) and (in)?


Regards,
--

TSa

unread,
Oct 23, 2006, 8:58:10 AM10/23/06
to perl6language
HaloO,

Jonathan Lang wrote:
> OK. My main dog in this race is the idea of defining new roles
> through the concepts of the intersection or difference between
> existing roles

Note that you should not call these 'intersection type' because
this term is used for the union of role interfaces. That is the
typist intersects the extension sets of objects doing the roles
that are combined. IOW, set operations for roles could also be
defined the other way around. If that solves the perceptive
dissonance of a typical Perl programmer that Larry mentioned,
I don't know.


> And yes, this "roles as sets" paradigm would presumably mean that you
> could examine roles using '⊂', '⊃', '∈', and so on. Given the
> semantic aspect of roles, I don't think that I'd go along with saying
> that 'A ⊃ B' is equivalent to 'A.does(B)' - although I _would_ agree
> that if 'A.does(B)' then 'A ⊃ B'. Rather, I'd think of 'A ⊃ B' as
> being the means that one would use for duck-typing, if one really
> wanted to (presuming that one can mess with how perl 6 does
> type-checking).

I guess up to now it is undefined how structural and how nominal the
Perl 6 type system is. But I agree that when a role A says that it
does B that the type system should check if A ⊃ B. I believe that it
should be possible to fill a node in the type lattice with a named
role precisely to catch dispatches to this intersection, union or
another combination interface. Or you instanciate parametric roles
for the same purpose.

Note that union interfaces might need some merging of signatures as
I tried to argue elsewhere. Also, we might allow the subrole to change
signatures in accordance with the intended subtype relation.


Regards, TSa.
--

Ruud H.G. van Tol

unread,
Oct 23, 2006, 8:58:36 AM10/23/06
to perl6-l...@perl.org
TSa schreef:

> A(|)B produces a subtype of A and B, and that A(&)B
> produces a supertype

Are you sure? I see "&" as "limiting; sub" and "|" as "enlarging;
super".
To me, "&" is connected to multiplication (and inproduct, statistics,
fuzzy logic), and "|" to addition (and outproduct).


$ perl -we 'printf "0x%02X\n", 0x0E & 0x33'
0x02

$ perl5 -we 'printf "0x%02X\n", 0x0E | 0x33'
0x3F

--
Groet, Ruud

Oops, I think I found a bug in sprintf:
$ perl5 -we 'printf "%#04X\n", 15'
0X0F
which AFAIK should print 0x0F, so with a lowercase x.

TSa

unread,
Oct 23, 2006, 9:29:19 AM10/23/06
to perl6-l...@perl.org
HaloO,

Ruud H.G. van Tol wrote:
> TSa schreef:
>
>> A(|)B produces a subtype of A and B, and that A(&)B
>> produces a supertype
>
> Are you sure?

Very sure ;)

In record subtyping a record is a mapping of labels to types.
In Perl 6 speak this is what a package does. One record type
is a subytpe if it has a superset of the label set and the
types of the common labels are subtypes. This record is the
intension set of types. When it grows the "number" of objects
in the extension set decreases. The limiting cases are the
universal set Any that has the empty intension set and Undef
or Whatever with the universal intension set but no defined
instances.


> I see "&" as "limiting; sub" and "|" as "enlarging;
> super".
> To me, "&" is connected to multiplication (and inproduct, statistics,
> fuzzy logic), and "|" to addition (and outproduct).

As I just wrote elsewhere this is the extensional view of the
sets underlying types. The extension of Bool e.g. is {0,1} and
that of Int is {...,-2,-1,0,1,2,...} from which one argues that
Bool is a subtype of Int and that Bool(&)Int (=) Bool. On the
interface side of things Bool has to support all methods that
Int has, e.g. +, -, *, and /. Note that both types are not closed
under these operations: 1 + 1 == 2, 5/4 == 1.25. Bool adds logical
operators like && and || to the intension set.


Regards, TSa.
--

Smylers

unread,
Oct 23, 2006, 9:37:59 AM10/23/06
to perl6-l...@perl.org
TSa writes:

> Ruud H.G. van Tol wrote:
>
> > TSa schreef:
> >
> > > A(|)B produces a subtype of A and B, and that A(&)B produces a
> > > supertype
> >
> > Are you sure?
>
> Very sure ;)

In which case that provides a handy example supporting Larry's
suggestion that this is confusing, with some people expecting it to work
exactly opposite to how it does.

It doesn't really matter which way is right -- merely having some people
on each side, all naturally deriving what makes sense to them -- shows
that implementing this would cause much confusion.

Smylers

TSa

unread,
Oct 23, 2006, 10:31:37 AM10/23/06
to perl6-l...@perl.org
HaloO,

Smylers wrote:
> In which case that provides a handy example supporting Larry's
> suggestion that this is confusing, with some people expecting it to work
> exactly opposite to how it does.

So the mere fact that there are two sets involved rules out the
set operators as well?


> It doesn't really matter which way is right -- merely having some people
> on each side, all naturally deriving what makes sense to them -- shows
> that implementing this would cause much confusion.

Better suggestions? Other than just writing one or the other in the
spec, I mean. I would opt for A(&)B producing the subtype on the
footing that this is usually called an intersection type, even though
the interfaces are merged.


Regards, TSa.
--

Jonathan Lang

unread,
Oct 23, 2006, 10:53:54 AM10/23/06
to perl6-l...@perl.org
Smylers wrote:
> TSa writes:
> > Ruud H.G. van Tol wrote:
> > > TSa schreef:
> > > > A(|)B produces a subtype of A and B, and that A(&)B produces a
> > > > supertype
> > >
> > > Are you sure?
> >
> > Very sure ;)
>
> In which case that provides a handy example supporting Larry's
> suggestion that this is confusing, with some people expecting it to work
> exactly opposite to how it does.

It's a terminology issue. The OO terms "subclass" and "superclass"
are counterintuitive, in that a "superclass" is more limited than the
"subclass" that is derived from it - that is, the "subclass" provides
a superset of the elements of the "superclass". I have studiously
avoided using that terminology for this very reason. Well, that and
the fact that we're talking about roles here, not classes; and
conceptually, roles are supposed to be more egalitarian than classes -
"super-role" and "sub-role" would carry too much of a hierarchal
connotation for what roles are supposed to be.

(&) and (|) would actually reflect your intuition regarding the
capabilities of the result, in that a role arrived at by means of (&)
would provide fewer options than the individual roles used to create
it, while a role arrived at by means of (|) would provide more
options.

> It doesn't really matter which way is right -- merely having some people
> on each side, all naturally deriving what makes sense to them -- shows
> that implementing this would cause much confusion.

I'll have to differ from you here. We (the language designers) get to
choose how the concepts get presented, and presentation is everything
(or pretty darn close). If we make a point of highlighting the "set
operations" perspective and avoiding traditional type theory
terminology (which, as Larry pointed out and TSa demonstrated, is very
much inside out from how most people think), we can avoid most of the
confusion you're concerned about.

--
Jonathan "Dataweaver" Lang

Jonathan Lang

unread,
Oct 23, 2006, 11:05:47 AM10/23/06
to perl6language
TSa <Thomas....@barco.com> wrote:
> I strongly agree. Having a language that allows supertying has novelty.
> But I think that union is not there for completion but as integral part
> when it comes to defining a type lattice which I still believe is the
> most practical approach to typing. This includes computed types, that
> is "artificial" nodes in the lattice. These intermediate types are
> usually produced during type checking and automatic program reasoning.
>
> Think e.g. of the type of an Array:
>
> my @array = (0,1,2); # Array of Int
> @array[3] = "three"; # Array of Int(&)Str

Actually, these would be something along the lines of "Array of Int"
and "Array of (Int, Int, Int, Str)", respectively. That is, each of
@array[0..2] would be of type "Int", while @array[3] would be of type
"Str". @array itself would be of type "Array" (which, without any
further qualifiers, is equivalent to "Array of Any"). If you must
force a more restrictive type on @array, go with "Array of (Int |
Str)" (yes, I do mean "|", not "(|)"; it's a type-matching issue, not
a container-construction issue.)

> > And yes, this "roles as sets" paradigm would presumably mean that you
> > could examine roles using '⊂', '⊃', '∈', and so on.
>
> BTW, are the ASCII equivalents spelled (<), (>) and (in)?

I'd hope that they'd be something like '(<)', '(>)', and 'in'; only
use parentheses when neccessary. Likewise, I'd want the "relative
complement" operator to be '-', not '(-)'.

--
Jonathan "Dataweaver" Lang

TSa

unread,
Oct 23, 2006, 11:25:37 AM10/23/06
to perl6-l...@perl.org
HaloO,

Jonathan Lang wrote:
> If we make a point of highlighting the "set operations" perspective

You know that there are two sets involved. So which one do you mean?


> and avoiding traditional type theory
> terminology (which, as Larry pointed out and TSa demonstrated, is very
> much inside out from how most people think), we can avoid most of the
> confusion you're concerned about.

Well, the type theory terminology has it all. You just have to be
careful what you pick and how you combine the terms. "Sub" and
"super" be it in class, role or type connotate an order that in fact
is there as a partial order or preferably as a lattice. The rest is
about choosing a syntax. I for my part can live happily with whatever
flipping of (&) and (|) we settle on as long as I know to which set
they apply.

That being said I would think that prior art dictates (&) as meaning
subtype creation. Which puts it in line with & for the all junction
and && as logical connective. Note that the counterintuitive notation
for pre-composed roles using | is gone. It still exists in the
signatures, though.


Regards, TSa.
--

TSa

unread,
Oct 23, 2006, 11:30:55 AM10/23/06
to perl6language
HaloO,

Jonathan Lang wrote:
>> BTW, are the ASCII equivalents spelled (<), (>) and (in)?
>
> I'd hope that they'd be something like '(<)', '(>)', and 'in'; only
> use parentheses when neccessary. Likewise, I'd want the "relative
> complement" operator to be '-', not '(-)'.

Funny. I would have hoped that the parens unequivocally indicate
set operations. The set difference should be (-) on the basis that
numeric minus should subtract their cardinalities much like it does
for arrays and hashes.


Regards, TSa.
--

Ruud H.G. van Tol

unread,
Oct 23, 2006, 11:47:57 AM10/23/06
to perl6-l...@perl.org
Jonathan Lang schreef:

> (&) and (|) would actually reflect your intuition regarding the
> capabilities of the result, in that a role arrived at by means of (&)
> would provide fewer options than the individual roles used to create
> it, while a role arrived at by means of (|) would provide more
> options.

OK, I am glad I asked about "sure" and that it is out of the way (for)
now.

--
Groet, Ruud

TSa

unread,
Oct 23, 2006, 11:38:33 AM10/23/06
to Jonathan Lang, perl6language
HaloO,

Jonathan Lang wrote:
>> my @array = (0,1,2); # Array of Int
>> @array[3] = "three"; # Array of Int(&)Str
>
> Actually, these would be something along the lines of "Array of Int"
> and "Array of (Int, Int, Int, Str)", respectively. That is, each of
> @array[0..2] would be of type "Int", while @array[3] would be of type
> "Str".

Oh, no. Array of (Int,Int,Int,Str) would prescribe every single
entry to be of the type (Int,Int,Int,Str) and I believe you need
to write Seq[Int,Int,Int,Str].


> @array itself would be of type "Array" (which, without any
> further qualifiers, is equivalent to "Array of Any"). If you must
> force a more restrictive type on @array, go with "Array of (Int |
> Str)" (yes, I do mean "|", not "(|)"; it's a type-matching issue, not
> a container-construction issue.)

Which is another argument for choosing '(|)' to mean supertype in
role combination.


Regards, TSa.
--

0 new messages