On Fri, Dec 12, 2003 at 05:17:37PM -0500, Austin Hastings wrote: : > -----Original Message----- : > From: Larry Wall [mailto:[EMAIL PROTECTED] : > Sent: Friday, December 12, 2003 12:17 PM : : > : - role : > : A collection of methods to be incorporated into a class sans : > : > A role can also supply one or more attributes. : : So a role can constrain values and add behavior and attributes. Presumably : it can do both at the same time?
I suspect so. Some added behaviors may only make sense on a constrained set of values. : enum ParityMode values <P_ODD P_EVEN P_NONE>; : : role Byte : does Int[0..255] # Value constraint : does { # extending by adding attributes & methods, and by : overriding the STORE method : has ParityMode $.parity_mode = NONE; : has bit $.parity; : : # .CONFORM is redundant with Value constraint above, : which autogenerates this. : method CONFORM(Int $i) { SUPER && 0 <= $i <= 255; } : method STORE(Int $i: $v) { $i = .CONFORM($v) || fail; set_parity; } : method set_parity {...} : }; Yes, though CONFORM is likely to be spelled PRE. And I'm not sure your STORE is gonna work by clobbering the invocant reference like that. More likely you have to assign to .value or some such accessor provided by Int. Or since roles compose into the class, it may be okay for roles to access attribute variables directly, and set $.value (presuming that's the attribute provided by Int). Depends on how fancy we want to get with the cross checking at composition time. : > : inheritance (and maybe some other stuff, too). Used : > with C<does>. : > : > Here it gets a little fuzzier. A role can be applied to a class : > at compile time via "does", or to an object at run time via "but". : : Good. I like the mixin being available at either time. This makes properties : a lot more useful since I can provided "default" or "normal" values: : : role Celebrated : does Date : does { : method celebrated($d) { return $d.date; } : } : : class Birthday does Celebrated { : has $.date; : } : : my Birthday $d = Birthday.new('February', 29, 2004) but : Celebrated('March', 01, 2004); : : print "My birthday is celebrated $d.celebrated"; More generally, you can write the rest of the class knowing that the role is there if it's compiled in. : I presume that the linear order (compile time) or chronological order of : applying roles decides the order in which overlaid methods are : C<wrap>ed/overlaid. The original Traits paper specifies that it's illegal to compose two methods of the same name into the class, and you have to rename one of them to get them both visible. This is why the authors specifically rejected mixins, because they hide errors like this. As for the relationship of "Trait" methods to other methods declarations, an explicit method declaration in the class proper overrides the composed methods, while composed methods override anything else in the inheritance hierarchy. : Which is it, by the way? Or is there MTOWTDI, such as a method modifier for : specifying polymorph behavior? The default way might well be the way specified in the Traits paper. However, their underlying language didn't support any kind of multi dispatch. Perl 6 will be able to "multi" any set of names in the same namespace as long as the arguments are differentiable by type. So it might be possible to insert a stub method declaration in the class proper that says "treat all composed methods of this name as multis". That presumes the methods take differing arguments, of course. : method CONFORM is wrapped { ... call ... } That would be another way to do it, except that you might still have to switch on something to tell it which role method to call. : > A property is a simple kind of role that supplies a single attribute. : > The type of a property is identical to its role name. Roles can have : > subtypes that function as enums when the subtypes are constrained to a : > single value. : : This seems really clunky for enums. It works okay for boolean, but even : doing month-names is going to suck pretty hard: : : role Month; : : role January does Month[0]; : role February does Month[1]; : role March does Month[2]; : role April does Month[3]; : role May does Month[4]; : role June does Month[5]; : role July does Month[6]; : role August does Month[7]; : role September does Month[8]; : role October does Month[9]; : role November does Month[10]; : role December does Month[11]; : : role Month does Int[January..December]; That's why I suggested some syntactic sugar for it. But I admit that treating each enum as a subtype is a stretch. They could be constant methods, for instance. In any event, the various enum names should probably be hidden in the Month role and not be exported by default. : > You can use one of these subtypes without specifically implying the role : name. So saying : > : > $bar but Red : > : > might give you a value with the property Color. : : This is smart and helpful. I like it. However, there needs to be a way to : specify what to do when multiple roles share the same values. For example, : if I have NeededBy and Estimated roles: : : my $birthday = "02/29/2004" but March; : my $ship_date = "01/01/01" but NeededBy(February); Conflicts within a class either need to be reported as soon as they're spotted, or dealt with by some kind of multi dispatch. There's no hiding or overriding within a composed class. : > You can write the corresponding boolean test using the smart match : operator: : > : > $bar ~~ Red : > : > and it (smartly) picks out the Color property to compare with, provided : > it's unambiguous. You can use that syntax to compare against any : > subtype or junction of subtypes: : > : > $bar ~~ Redish&Whiteish # pinkish : > : : Disambiguation? : : $bar ~~ NeededBy(February) : : or : : $bar.NeededBy ~~ February Certainly the second form should work, unless it blows up because there's no NeededBy property. Not sure about the parens on the first form, but there has to be some syntax that makes the type of an enum explicit, and that form is probably going to be preferred if the second form blows up on non-existent properties. And the syntax needs to support something like NeededBy[January|July] so NeededBy::January is probably not going to cut it. Larry