Re: where constraints as roles (was Re: how typish are roles)
TSa wrote: IOW, I fear this could only be put to work with two subset declarations subset ab of Str where /^a.*b$/; subset aabb of ab where /^aa.*bb$/; and the notion that the second subset by virtue of constraining the possible values further produces a more specific subtype for dispatch. That is nominal subtyping. Perl 6 already uses nominal subtyping: S02 - "Types are officially compared using name equivalence rather than structural equivalence." There's further elaboration which addresses many of the concerns involved with using nominal subtyping, so I'd suggest reading the section in question before commenting. BTW, the above example is a good case for introducing the subtype relation operator <: because we have aabb <: ab <: Str but do we also have aabb.does(ab) and ab.does(Str)? Could we also state that aabb (<) ab (<) Str? Regards, TSa. -- -- Jonathan "Dataweaver" Lang
Re: where constraints as roles (was Re: how typish are roles)
HaloO, Jonathan Lang wrote: At its core, a type is nothing more than a constraint on the objects that a given variable is allowed to handle; this would put C clauses at the center of the type system, with roles coming in a very close second due to the implicit use of ".does()" in the compact syntax. Great idea! I like the unification of everything typish under the umbrella of (type) constraints. These predicates then need to be amenable to subsumption and entailment forming the dispatch lattice. Of course the sublanguage for where clauses has to be a restricted subset of full Perl 6. Otherwise you can't do machine proofs. This view is shared by mmd-draft.txt, it states that conceptually all dispatch relevant informations are predicates. Hmm, having regular expressions in where clauses already raises the question if one can treat them programatically. E.g. a 'where /^aa.*bb$/' is strictly more specific than 'where /^a.*b$/'. But can that be calculated in a deterministic fashion? Would dispatch at least work on a case by case basis? Or would we get ambiguity errors because of principal incomparability of the two clauses? IOW, I fear this could only be put to work with two subset declarations subset ab of Str where /^a.*b$/; subset aabb of ab where /^aa.*bb$/; and the notion that the second subset by virtue of constraining the possible values further produces a more specific subtype for dispatch. That is nominal subtyping. BTW, the above example is a good case for introducing the subtype relation operator <: because we have aabb <: ab <: Str but do we also have aabb.does(ab) and ab.does(Str)? Could we also state that aabb (<) ab (<) Str? Regards, TSa. --
Re: how typish are roles
HaloO, Jonathan Lang wrote: Larry Wall wrote: But I'm still somewhat set against the notion of using logical ops to do set theory. (Even if you put parens around them.) Understandably so. Perhaps "(u)" and "(n)" would be better ASCII equivalents for the union and intersection operators... Hmm, I think using the dualism between set operations and boolean operations is a good thing. Note that there is an isomorphism between &&, || and ! for the logical side and (&), (|) and (!) for sets---DeMorgan etc. We could even introduce low precedence versions (and), (or) and (not). Well, and of course (^) and (xor) corresponding to ^^ and xor. They all form nice mnemonics for each other. Regards, TSa. --
Re: where constraints as roles (was Re: how typish are roles)
On Saturday 28 October 2006 09:15, Larry Wall wrote: > My initial inclination is to say that "where" clauses in a signature > are only there for pattern matching, and do not modify the official > type of the parameter within the function body. However, on a "subset" > the "where" clause is there precisely to contribute to the typing, > so if you want the extra constraints to apply to all uses of the > parameter variable within the body, you'd need to declare a subset > type that enforces it. Right; it's awfully difficult to have nominal typing in a room full of blank "Hello my name is" tags. > On the other hand, I can imagine that an alternative would be to say > that a "where" clause will always "subsetize" the official type; > that would imply that we'd need to add a "when" clause for mere > pattern matching. Something to be said for making such a distinction, > if it can be taught. -- c
Re: how typish are roles
Larry Wall wrote: But I'm still somewhat set against the notion of using logical ops to do set theory. (Even if you put parens around them.) Understandably so. Perhaps "(u)" and "(n)" would be better ASCII equivalents for the union and intersection operators... -- Jonathan "Dataweaver" Lang
Re: where constraints as roles (was Re: how typish are roles)
Trey Harris wrote: Trey Harris writes: > chromatic writes: >> When you specify a type to constrain some operation, you specify that the >> target entity must perform that role. > > That statement is very concise and direct. If the fuzziness I observed about > the identity of the basic building block of type was unintentional, this > statement should be added to S06. S02 already has q[A variable's type is a constraint indicating what sorts of values the variable may contain. More precisely, it's a promise that the object or objects contained in the variable are capable of responding to the methods of the indicated "role".] Incidentally, this would mean that a C clause or junctive type defines an anonymous role, and a type parameter defines a lexical role, doesn't it? Seems like a useful characteristic of these constructs to make explicit, perhaps in L. IMHO, this gets it backward. You shouldn't turn C clauses and junctive types into roles; you should turn roles and junctive types into C constraints: "Foo $x" is, in effect, shorthand for something like "$x where { .does(Foo) }", while "Foo | Bar Baz $x" becomes something like "$x where { .does(Foo) || .does(Bar) && .does(Baz) }". At its core, a type is nothing more than a constraint on the objects that a given variable is allowed to handle; this would put C clauses at the center of the type system, with roles coming in a very close second due to the implicit use of ".does()" in the compact syntax. IMHO, @Larry got overly precise in the above S02 quote: s[More precisely] = "Usually". -- Jonathan "Dataweaver" Lang
Re: how typish are roles
On Thu, Oct 26, 2006 at 03:17:27PM +0200, TSa wrote: : HaloO, : : I wrote: : >2) We have A&B and the A B juxtaposition to mean $_ ~~ A && $_ ~~ B : > which is an intersection (sub)type of A and B. : : Is the A&B form a legal alternative for the juxtaposition? Not in a signature. It's ambiguous with A &B where &B is declaring a routine type that returns A. Might be made to work in parens someday. But I'm still somewhat set against the notion of using logical ops to do set theory. (Even if you put parens around them.) Larry
Re: where constraints as roles (was Re: how typish are roles)
My initial inclination is to say that "where" clauses in a signature are only there for pattern matching, and do not modify the official type of the parameter within the function body. However, on a "subset" the "where" clause is there precisely to contribute to the typing, so if you want the extra constraints to apply to all uses of the parameter variable within the body, you'd need to declare a subset type that enforces it. On the other hand, I can imagine that an alternative would be to say that a "where" clause will always "subsetize" the official type; that would imply that we'd need to add a "when" clause for mere pattern matching. Something to be said for making such a distinction, if it can be taught. Fuzzily yours, Larry
where constraints as roles (was Re: how typish are roles)
In a message dated Sat, 28 Oct 2006, Trey Harris writes: In a message dated Sat, 28 Oct 2006, chromatic writes: When you specify a type to constrain some operation, you specify that the target entity must perform that role. That statement is very concise and direct. If the fuzziness I observed about the identity of the basic building block of type was unintentional, this statement should be added to S06. Incidentally, this would mean that a C clause or junctive type defines an anonymous role, and a type parameter defines a lexical role, doesn't it? Seems like a useful characteristic of these constructs to make explicit, perhaps in L. I find this a little unintuitive given the way these typing particles are used, though... If I were insane in a different way than I actually am, I might think I could use this "every constraint is a role" behavior to write: sub pairs_up_to (Int $x where { $^x % 2 == 0 } ) { (1..^$x:by(2)) >>=><< (2..$x:by(2)) } pairs_up_to(4)};# 1 => 2, 3 => 4 try { pairs_up_to(3) } err say $!; # "No compatible subroutine found" my $even_three = 3 but where { $_ % 2 == 0 }; # Huh? try { pairs_up_to($even_three) } err say $!;# What? Not a useful example, I admit--which is why I had assumed C constraints were not roles, because I can't think of a useful example of treating them as roles. But I suppose if you're determined to shoot yourself in the foot like that, you'll find some way (like overloading C<%> so it always returns 0). You could probably even make Perl be able to call the sub in the second C, perhaps by making the anonymous roles generated by C first match by AST equivalence before testing their value against the constraint or something. Not that I think Perl should be able to do that... I'm just saying I *might* think it would, given how roles usually work (and if I could come up with a less contrived case, I might actually expect it to). But *why* wouldn't it work? One of two reasons I think: 1. The first C clause in the sub signature defines a different anonymous role from the second C clause after C, even though they're defined identically. In that case, $even_three would have no practical difference from any other 3, because it merely mixes in a role that never gets used. 2. The assignment would throw a mistyped value exception, just like "my Num $foo = 'hi, mom'" does. (Except it doesn't. Should it? I don't see a test that addresses this in the suite, nor something in the Synopses to say that that assignment should fail.) In either case, C clauses create roles that values might do without even realizing they're doing them, and which mutable objects might do and then not do, willy-nilly, even in the course of the scope in which they were typed to do it... which I think is new unless I just haven't been paying attention. sub saturate (Color $c where { $^c.saturation < 100 } ) { $c.saturation = 100; # ??? correct_gama($c); } Did that mutation throw an exception, by changing $c's type to one it can't have in this sub? If no, did we just lose gradual typing (assuming correct_gamma cares)? Can we detect that, or do the roles created by C not participate in gradual typing? If C constraints weren't roles, this would make sense to me again. It's duck-typing, but a very different type of duck typing than, say Ruby has... it isn't a duck because it walks and quacks, but because when you examine it with your particular duckish litmus test (your C clause), the litmus test turns the duckish color (Bool::True) you're looking for. A trifling issue, I guess, as you can just ignore how C works so long as it does work. But when I see a statement like "every X is really syntactic sugar for a Y", I want to poke at all the X's to see how they behave deeply as Y's. Trey
Re: how typish are roles
In a message dated Sat, 28 Oct 2006, chromatic writes: When you specify a type to constrain some operation, you specify that the target entity must perform that role. That statement is very concise and direct. If the fuzziness I observed about the identity of the basic building block of type was unintentional, this statement should be added to S06. I think the question (which you didn't directly raise, but I've heard from others) of whether "role" or "class" will have primacy is kind of as pointless as asking whether "subroutines" or "code blocks" have primacy: you can't use the former without the latter; the former is a useful abstraction for the latter, especially when code gets larger or is meant for sharing; and while each have places where they're more appropriate, either can be used in place of the other given a bit of syntactic twiddling. Well... maybe. I believe strongly that you can build a really good system with roles as the fundamental abstraction and where classes are a specialization, but doing the other way around is much more difficult and less cohesive. But I wasn't suggesting that, any more than I was suggesting that code blocks based on anonymous subroutines would be as cohesive as subroutines based on code blocks. I was just saying that both roles and classes could be equally first-class participants in the type system by my reading of S06 and S12: I don't see any necessity, short a statement like yours I quoted above, for classes to be coerced into a role before they can act as a type. Trey
Re: how typish are roles
On Wednesday 25 October 2006 03:04, Trey Harris wrote: > I'll let @Larry speak for @Larry, but at one point I was told that when > C or C appear in signatures, those are roles, not classes; if > you examined a particular Array or Hash, the class would be some > implementation of the Array or Hash role, perhaps something like > C or C or so on. So I'd tend to agree > that roles "are the heavyweights in the type department." Yes. When you specify a type to constrain some operation, you specify that the target entity must perform that role. > Unless you're actually composing or inheriting from something, you > shouldn't care whether its type derives from a role, a class, a type set, > or a type parameter. Yes. > I think the question (which you didn't directly raise, but I've heard from > others) of whether "role" or "class" will have primacy is kind of as > pointless as asking whether "subroutines" or "code blocks" have primacy: > you can't use the former without the latter; the former is a useful > abstraction for the latter, especially when code gets larger or is meant > for sharing; and while each have places where they're more appropriate, > either can be used in place of the other given a bit of syntactic > twiddling. Well... maybe. I believe strongly that you can build a really good system with roles as the fundamental abstraction and where classes are a specialization, but doing the other way around is much more difficult and less cohesive. > I can read S12 as saying that classes always do an eponymous role, and so > role is what typing is "really" based on. Yes. > In other words, I agree that it's fuzzy, but I personally read the > fuziness as intentional, so as to allow implementations flexibility and > prevent bad dependencies on particular "inner workings" of the type > system. That fuzziness is classic $Larry. Some of the rest of @Larry can be more *mumble*matic. -- c
Re: how typish are roles
HaloO, I wrote: 2) We have A&B and the A B juxtaposition to mean $_ ~~ A && $_ ~~ B which is an intersection (sub)type of A and B. Is the A&B form a legal alternative for the juxtaposition? --
Re: how typish are roles
HaloO, Jonathan Lang wrote: 2) We have A&B and the A B juxtaposition to mean $_ ~~ A && $_ ~~ B which is an intersection (sub)type of A and B. Not according to my reading of S06: if you want to force a parameter to match both of two different roles, you must use a where clause. In section "Polymorphic types" S06 reads: "Since the terms in a parameter could be viewed as a set of constraints that are implicitly "anded" together (the variable itself supplies type constraints, and where clauses or tree matching just add more constraints), we relax this to allow juxtaposition of types to act like an "and" junction:" The following example also makes it clear that a joined interface is meant. So I think a where clause it not needed. Regards, TSa. --
Re: how typish are roles
TSa wrote: I want to summarize what we have so far. 1) In type constraint position we can say things like A|B to effectively mean a supertype of A and B by virtue of $_ ~~ A || $_ ~~ B. Right. This would be equivalent to "Any where {.does(A) or .does(B)}". 2) We have A&B and the A B juxtaposition to mean $_ ~~ A && $_ ~~ B which is an intersection (sub)type of A and B. Not according to my reading of S06: if you want to force a parameter to match both of two different roles, you must use a where clause. 3) The junctive ops |, & and ^ can be used in where clauses to form type constraints. How does that apply to any(), all(), one() and none()? Are they allowed as well? With none() we effectively get type complement. AFAICT, any() can be used (almost) anywhere that infix:<|> can be; ditto with the other junctive ops and their associated functions. In particular, I see no reason why they would be forbidden in where clauses. (The one case where "any" might not be usable as a substitute for infix:<|> is point 1, above. Even then, I'm not really certain that it can't be used.) 4) The junctive ops and the set operators (|) and (&) are *not* yet available as type constructors in role definitions, that is things like 'role does A(&)B'. Correct. If there's a queue being maintained for post 6.0 features, I'm hoping that it's in the queue; but it isn't going to be a 6.0 feature AFAIK. Does recursive use of roles in their own definition produce F-bounds? role A does Gen[A] {...} I don't see why not. Heck, while it would usually be silly to do so, I could even see cyclic role definitions working: role A does B { ... } role B does A { ... } or even role A does A { ... } (though why any role would ever want to compose itself is beyond me.) -- Jonathan "Dataweaver" Lang
Re: how typish are roles
HaloO, Trey Harris wrote: In other words, I agree that it's fuzzy, but I personally read the fuziness as intentional, so as to allow implementations flexibility and prevent bad dependencies on particular "inner workings" of the type system. Thanks for the support. I figured that I've asked the same question more than a year ago. I want to summarize what we have so far. 1) In type constraint position we can say things like A|B to effectively mean a supertype of A and B by virtue of $_ ~~ A || $_ ~~ B. 2) We have A&B and the A B juxtaposition to mean $_ ~~ A && $_ ~~ B which is an intersection (sub)type of A and B. 3) The junctive ops |, & and ^ can be used in where clauses to form type constraints. How does that apply to any(), all(), one() and none()? Are they allowed as well? With none() we effectively get type complement. 4) The junctive ops and the set operators (|) and (&) are *not* yet available as type constructors in role definitions, that is things like 'role does A(&)B'. To comply with 2) this should create an intersection type even though it joins the interfaces of A and B. Does recursive use of roles in their own definition produce F-bounds? role A does Gen[A] {...} or perhaps role A where A.does(Gen[A]) {...} Regards, TSa. --
Re: how typish are roles
In a message dated Wed, 25 Oct 2006, TSa writes: from the recent threads 'class interface of roles', 'set operations for roles' and 'signature subtyping and role merging' I wonder how typish roles actually are. Some seem to consider roles as lightweight particles that serve to compose classes. I see them as the heavyweights in the type department. Doing a role is like a contract about certain functionality. So, what does @Larry think? I'll let @Larry speak for @Larry, but at one point I was told that when C or C appear in signatures, those are roles, not classes; if you examined a particular Array or Hash, the class would be some implementation of the Array or Hash role, perhaps something like C or C or so on. So I'd tend to agree that roles "are the heavyweights in the type department." I've spent a few minutes with no luck trying to draw the actual discussion out of the #perl6 logger, but I'm pretty sure this was the gist. My (probably lame) interpretation of the Weltanschauung of Perl's typing is that roles, classes, type parameters, and type sets (junctive types, subsets, and mixtures thereof) are all equally relevant to the type system, and are all equally "typish" (though perhaps some are more primitive and some are more sugary). Unless you're actually composing or inheriting from something, you shouldn't care whether its type derives from a role, a class, a type set, or a type parameter. (And if you are composing or inheriting from it, you're not so much interested in its typishness as its behavior. Your new type will be/do whatever type(s) it inherited/composed, and will also be/do itself; beyond that, you shouldn't care) My gut feeling is that in real-world Perl 6 code we'll see a lot of both classes and roles being used as types. Roles will be more common typing particles when interacting with the Perl core or parts of other large code bases, and when you desire type safety. Classes will be more common when you just have a local need to have something to instantiate, or you want SMD or MMD. When programming in the large, the benefits of having a role will often be clearer; when programming in the small, a class will often (C not always ;) be more expeditious. I think the question (which you didn't directly raise, but I've heard from others) of whether "role" or "class" will have primacy is kind of as pointless as asking whether "subroutines" or "code blocks" have primacy: you can't use the former without the latter; the former is a useful abstraction for the latter, especially when code gets larger or is meant for sharing; and while each have places where they're more appropriate, either can be used in place of the other given a bit of syntactic twiddling. I know that S12 states "The type system of Perl consists of roles, classes, and subtypes" but I don't have a clear picture of the inner workings or the formal model of this type system. E.g. what actually constitutes a type? How are the classes related to types? There is this fuzzy concept that a class is also a role of the same name as far as typing is concerned. How is the subtyping relation defined? I can read S12 as saying that classes always do an eponymous role, and so role is what typing is "really" based on. Or alternatively, since when a role is used as if it were a class, it constructs an anonymous class that composes it, that class is what typing is "really" based on. But I don't see that it matters one way or the other; they seem functionally equivalent to me--as would having type based on C subsets, or having all these things participate equally, or any other angle you might want to look at it from. The behavior seems pretty ecumenical to me. In other words, I agree that it's fuzzy, but I personally read the fuziness as intentional, so as to allow implementations flexibility and prevent bad dependencies on particular "inner workings" of the type system. Trey
how typish are roles
HaloO, from the recent threads 'class interface of roles', 'set operations for roles' and 'signature subtyping and role merging' I wonder how typish roles actually are. Some seem to consider roles as lightweight particles that serve to compose classes. I see them as the heavyweights in the type department. Doing a role is like a contract about certain functionality. So, what does @Larry think? I know that S12 states "The type system of Perl consists of roles, classes, and subtypes" but I don't have a clear picture of the inner workings or the formal model of this type system. E.g. what actually constitutes a type? How are the classes related to types? There is this fuzzy concept that a class is also a role of the same name as far as typing is concerned. How is the subtyping relation defined? Regards, TSa. --