Roles and Mix-ins?
I'm still digesting the vocabulary thread, but while I do, let me ask a question that's probably crystal clear to everyone else. Do roles act as a form of mix-in, as Ruby modules may, and Objective-C protocols do? Would the following two snippets be at all equivalent? # Perl6 role Talk { method say_hello { print "Hello world!\n" } } class Foo does Talk { ... } Foo.new.say_hello; # Ruby module Talk def say_hello puts "Hello world!" end end class Foo include Talk end Foo.new.say_hello --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.545 / Virus Database: 339 - Release Date: 11/27/2003
Re: Roles and Mix-ins?
Chris Shawmail (E-mail) writes: > I'm still digesting the vocabulary thread, but while I do, let me ask a > question that's probably crystal clear to everyone else. > > Do roles act as a form of mix-in, as Ruby modules may, and Objective-C > protocols do? > > Would the following two snippets be at all equivalent? Probably, depending on what's in the eventual definition of Foo. Roles are quite similar to mixins (as the Traits paper said that they were inspired by mixins), but they're distinctly not the same. For one, one role's methods don't silently override another's. Instead, you get, er, role conflict and you have to disambiguate yourself. For two, you can attach new roles to an object at runtime (I don't know if you can do this with mixins, actually). > # Perl6 > role Talk { >method say_hello { > print "Hello world!\n" >} > } > > class Foo does Talk { ... } > > Foo.new.say_hello; > > # Ruby > module Talk >def say_hello > puts "Hello world!" >end > end > > class Foo >include Talk > end > > Foo.new.say_hello Luke
Re: enums and bitenums
Larry Wall wrote: > Well, we can't use -> because we're using that for something else. > But it's certainly true that we'll have to have some mechanism for > disambiguating Color.green from Blackberry.green. After all, > > Blackberry.green == Color.red > > Or maybe it's > > Blackberry::green == Color::red [...] > I don't know the syntax for > disambiguating on the green end yet. Maybe one of > > $foo ~~ Color::green > $foo ~~ Color.green > $foo ~~ Color[green] > > Or maybe something else. How about a single colon? Color:green This is the same syntax employed in XML namespaces and URIs, for example: http://example.com/xml/color.xsd";> Don't tell me, we can't use : because we're using that for something else. :-) Presumably, the parser could be smart enough to entuit the role on either side of a comparison if the other is specified. $foo:Color ~~ Color:green $foo ~~ Color:green # assumes $foo:Color $foo:Color ~~ green # assumes Color:green > I'm thinking the ordinary method > > $foo.Color > > implies > > $foo.as(Color) What if your $foo object has a regular method called Color? Would it get called in preference? A
Re: enums and bitenums
Andy Wardley writes: > Larry Wall wrote: > > Well, we can't use -> because we're using that for something else. > > But it's certainly true that we'll have to have some mechanism for > > disambiguating Color.green from Blackberry.green. After all, > > > > Blackberry.green == Color.red > > > > Or maybe it's > > > > Blackberry::green == Color::red > > [...] > > > I don't know the syntax for > > disambiguating on the green end yet. Maybe one of > > > > $foo ~~ Color::green > > $foo ~~ Color.green > > $foo ~~ Color[green] > > > > Or maybe something else. > > How about a single colon? > > Color:green > > This is the same syntax employed in XML namespaces and URIs, for example: > > http://example.com/xml/color.xsd";> > > > > Don't tell me, we can't use : because we're using that for something > else. :-) Well, yes. It's used in the operator position already for the indirect object syntax, so I don't think that'll fly. Keeping with the color example, let's think about what this is doing: $foo ~~ green That ought to work even if you set "green" by saying: $foo.Color = (0,1,0); So it seems more that "green" is doubling as a predicate and a value. Indeed, you could think of setting something to green as setting it to "pure green" (0,1,0), but testing "green" as anything that looks greenish -> $r,$g,$b { $g > $r + $b }. Maybe it's a subtype[1] of the property with a default value? That gets me thinking about how to declare that. If a subtype is like a parameter to the class that the class didn't really declare, I could imagine a syntax like this: constraint Color[green] { $.g > $.r + $.b } That makes me woosy, though. Maybe digging up the adverbial modifier C should stir some ideas. constraint green is Color { $.g > $.r + $.b } my Color where green $spinach; Maybe we'd better leave that one buried. For some reason, subtypes don't feel like roles to me. They're not so much behaviors are they are constraints... on behavior. Like the opposite of roles, actually. Oh, we were talking about enums, right? Um. Yeah. Luke [1] There's a term to add to the vocab sheet. AFAIK, a subtype is a variation on a normal type that has some constraint applied to it. Think vague.
Re: enums and bitenums
--- Larry Wall <[EMAIL PROTECTED]> wrote: > On Fri, Dec 12, 2003 at 03:10:30PM -0800, Paul Hodges wrote: > : Ok, wait a sec. Does that mean different references to the same > : critter can have differing sets of aspects? > : > : my Dog $Spot; > : my $doggie = Dog.new(); > : my $meandog = \$doggie.as(AttackDog); > : my $nicedog = \$doggie.as(LapDog); Forgive me, I'm trying to get accustomed to the new syntax, so let me rewrite > : if $me.away { > : if $visitor.nephew { > :$Spot = $nicedog; > : } else { > :$Spot = $meandog; > : } > : } as $Spot = $visitor.nephew ?? $nicedog :: $meandog; Which brings up a small side note: that's a successfully applied boolean context for $visitor.nephew, right? > : Now, if I'm away and someone show up, I presume that if it's my > : nephew then $Spot.seeVisitor() will invoke the LapDog role's .wag() > : method, but otherwise I expect it to invoke the AttackDog role's > : .Bark() method. I realize there are other ways to get here > : but would this *work*??? > > We might be able to make it work, though as you say, there are other > ways to get there, and the chances are that at least one of them will > be a better way. lol -- yeah. This is the kind of code I find six months after writing it and wonder what sort of delerium I was suffering that day. So what exactly does it mean to have a "typed reference"? $meandog still a Dog, just using an AttackDog role, right? So it's type is Dog&AttackDog? Inheritance thinking starts crowding in here and blurring my understanding of what's going on. > Certainly when the Dog object's class is composed, it > will have to do something about the conflicting .seeVisitor methods > in the two roles. Ah! The class has to reconcile the roles used to build it. That would cause the same conflict between AttackDog.Bark() and LapDog.Bark(), if each had one, but that certainly falls back to a matter of design, and that there are better ways to build it. I wish I had generated a better example, but for the sake of consistency, I'll work with what we've already got, so how about predefining defaults to resolve known conflicts? class Dog does LapDog {...}; Dog.bark is default(LapDog); # I lowercased .bark() here class Dog does AttackDog; my Dog $Spot = Dog.new(); $Spot.bark(); # yip, yip $Spot.AttackDog.bark(); # sick 'em! I just noticed I had uppercased my method(s), and it was annoying me. Anyway, that syntax looks really freaky to me. I can look at it and know what it was *meant* to do, but how would it be implemented? Dog.bark but= LapDog; didn't look any better, though. :( Obviously I'm not awake yet, but maybe these rambles will be useful to somebody? > It might well be better to encode that choice as > part of the dog's state rather than in the references to it. I'd say that was almost guaranteed to be the better way to go in practice. I've just seen too many cases where I was handed poorly designed legacy code and expected to hack it into some new functionality, "oh and we need that by three today?" My workplace considers refactoring to be reinventing the wheel. Just add another motor and axle over here!! sheesh, lol > On the other hand, it might just fall out of our implementation > that it does the right thing with typed references, if the method > dispatch to the conflicting methods in the Dog class can have access > to the reference types to break ties. And since the type of the ref could be Dog&LapDog&AttackDog&Pet, that should work. :) > : And btw, just a refresher on this "assigning a ref" thing -- would > : the syntax have to change at *all*? > > Dunno. I don't see anything obviously wrong with it, but then I > never could see very well... Yeah, right. :) > Larry Paul __ Do you Yahoo!? New Yahoo! Photos - easier uploading and sharing. http://photos.yahoo.com/
RE: Vocabulary
> From: Larry Wall [mailto:[EMAIL PROTECTED] > > On Fri, Dec 12, 2003 at 04:27:59PM -0500, Austin Hastings wrote: > : > -Original Message- > : > From: Jonathan Scott Duff [mailto:[EMAIL PROTECTED] > : > I think I'm getting it but I'm not sure. Does something like this > : > work? > : > > : > my role Teach { ... } > : > my role Operate { ... } > : > my role Learn { ... } > : > > : > my Person $frank; > : > { temp $frank_the_teacher = $frank does Teach; ... } > : > { temp $frank_the_doctor = $frank does Operate; ... } > : > { temp $frank_the_student = $frank does Learn; ... } > : > > : > I.e., we can use dynamic scoping to control how long an object > : > fulfills a particular role? Maybe it could also be written like so: > : > > : > my Person $frank; > : > { my role Teach { ... }; $frank does Teach; ... } > : > { my role Operate { ... }; $frank does Operate; ... } > : > { my role Learn { ... } $frank does Learn; ... } > : > > : > so that when the role goes out of scope, the object no longer > : > possesses the abilities of that role. > : > > : > I confuse myself everytime I think about this stuff. > : > : That's brilliant, if twisted. The object persists, but the > behaviors expire. > : There's a paradigm there, man. Write a book. > > The behavior probably doesn't expire unless you've cloned the object > and the clone expires. However, if a role goes out of its lexical > scope, it can't be named, so it's effectively not usable unless you > dig out a name for it via reflection. But the information is still > cached there, so the object could be smarter the next time it takes > on the same role. It's a role closure, in other words? That being the case, how to you unapply a role? $frank does no Teach; $frank doesnt Teach; > That being said, a role applied with C probably *should* be > stripped out when it goes out of scope. Could get messy though... I can't think of a way to apply a role with temp (to a non-temp object). How do you do it? =Austin
RE: enums and bitenums
> -Original Message- > From: Larry Wall [mailto:[EMAIL PROTECTED] > Sent: Friday, December 12, 2003 7:39 PM > To: Perl6 > Subject: Re: enums and bitenums > > > On Fri, Dec 12, 2003 at 03:10:30PM -0800, Paul Hodges wrote: > : Ok, wait a sec. Does that mean different references to the same critter > : can have differing sets of aspects? > : > : my Dog $Spot; > : my $doggie = Dog.new(); > : my $meandog = \$doggie.as(AttackDog); > : my $nicedog = \$doggie.as(LapDog); > : if $me.away { > : if $visitor.nephew { > :$Spot = $nicedog; > : } else { > :$Spot = $meandog; > : } > : } > : > : Now, if I'm away and someone show up, I presume that if it's my nephew > : then $Spot.seeVisitor() will invoke the LapDog role's .wag() method, > : but otherwise I expect it to invoke the AttackDog role's .Bark() > : method. I realize there are other ways to get here but would this > : *work*??? > > We might be able to make it work, though as you say, there are other > ways to get there, and the chances are that at least one of them will > be a better way. Certainly when the Dog object's class is composed, it > will have to do something about the conflicting .seeVisitor methods > in the two roles. Hmm. What does that do for run-time behavior? If you have to worry about (essentially) every possible role's namespace conflicting with every other, the whole thing risks getting less useful quickly. > It might well be better to encode that choice as > part of the dog's state rather than in the references to it. Treat 'em as a stack. Last one applied dominates. But make sure there's a way to unstack the roles when finished. > On the > other hand, it might just fall out of our implementation that it does > the right thing with typed references, if the method dispatch to > the conflicting methods in the Dog class can have access to the reference > types to break ties. That's cool.
RE: Vocabulary
> -Original Message- > From: Larry Wall [mailto:[EMAIL PROTECTED] > Sent: Friday, December 12, 2003 8:30 PM > On Fri, Dec 12, 2003 at 05:17:37PM -0500, Austin Hastings wrote: > : 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 > : Ced/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. I'm not convinced these are errors. Having a role override methods makes sense in a lot of ways. Consider, for example, a caching or persistence implementation that overrides the .STORE method of its victims. It seems to me there's an argument both ways -- 1. Code written in the absence of a role won't anticipate the role and therefore won't take (unknowable) steps to disambiguate method calls. Ergo method overloads are bad. 2. Roles may be written to deliberately supercede the methods of their victims. Method overloads are vital. This doesn't take into account role vs. role conflicts (which seem more likely to be serendipitous). Perhaps an "exact signature" rule would work? Such that if the method was an exact replacement, then no error occurs, otherwise it becomes either an error or a multi? Alternatively, perhaps a role must declare its method to be multi or not, and if not then the role's method overloads the original class's. (Which takes us to retroactive multi-fication. Ugh.) Or perhaps you just have to say "this method overloads". > 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. At compile time, right? Whereas composition (but=) overrides declaration at run-time? > : 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 Augustdoes 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. Yeah, the concept is useful enough that it's probably worth a spoonful of sugar. Perhaps it were better to think of a clever way of defining a batch of named constants in a class declaration, so that enums could be full classes if they want to be: class Month is Int { method name {...}; has values [ January => 0, February, ..., December ]; } > : > You can use one of the
RE: enums and bitenums
> -Original Message- > From: Luke Palmer [mailto:[EMAIL PROTECTED] > Sent: Saturday, December 13, 2003 9:30 AM > To: Andy Wardley; Larry Wall; Perl6; [EMAIL PROTECTED] > Subject: Re: enums and bitenums > > > Andy Wardley writes: > > Larry Wall wrote: > > > Well, we can't use -> because we're using that for something else. > > > But it's certainly true that we'll have to have some mechanism for > > > disambiguating Color.green from Blackberry.green. After all, > > > > > > Blackberry.green == Color.red > > > > > > Or maybe it's > > > > > > Blackberry::green == Color::red > > > > [...] > > > > > I don't know the syntax for > > > disambiguating on the green end yet. Maybe one of > > > > > > $foo ~~ Color::green > > > $foo ~~ Color.green > > > $foo ~~ Color[green] > > > > > > Or maybe something else. > > > > How about a single colon? > > > > Color:green > > > > This is the same syntax employed in XML namespaces and URIs, > for example: > > > > http://example.com/xml/color.xsd";> > > > > > > > > Don't tell me, we can't use : because we're using that for something > > else. :-) > > Well, yes. It's used in the operator position already for the indirect > object syntax, so I don't think that'll fly. Also, as Larry pointed out there's likely to be the need to talk about multiple values. Color[green|red] is better in a lot of ways than Color::green|Color::red. > Keeping with the color example, let's think about what this is doing: > > $foo ~~ green > > That ought to work even if you set "green" by saying: > > $foo.Color = (0,1,0); > > So it seems more that "green" is doubling as a predicate and a value. > Indeed, you could think of setting something to green as setting it to > "pure green" (0,1,0), but testing "green" as anything that looks > greenish -> $r,$g,$b { $g > $r + $b }. > > Maybe it's a subtype[1] of the property with a default value? > > That gets me thinking about how to declare that. If a subtype is like a > parameter to the class that the class didn't really declare, I could > imagine a syntax like this: > > constraint Color[green] { $.g > $.r + $.b } > > That makes me woosy, though. Maybe digging up the adverbial modifier > C should stir some ideas. > > constraint green is Color { $.g > $.r + $.b } > > my Color where green $spinach; I don't understand where you were going with that. > Maybe we'd better leave that one buried. Speaking of predicate/value mixups: role green does Color[$.g > $.r + $.b] does { method .VALUE { return (0,1,0); } }; Then: my Color $g = green; my Color $c = (random(), random(), random()); if $c == $g { print "That's GREEN!"; } elsif $c ~~ green { print "Well, it's greenish"; } > For some reason, subtypes don't feel like roles to me. They're not so > much behaviors are they are constraints... on behavior. Like the > opposite of roles, actually. > > Oh, we were talking about enums, right? Um. Yeah. > > Luke > > [1] There's a term to add to the vocab sheet. AFAIK, a subtype is a > variation on a normal type that has some constraint applied to it. > Think vague. >
Re: Roles and Mix-ins?
On Sat, Dec 13, 2003 at 04:57:17AM -0700, Luke Palmer wrote: : Chris Shawmail (E-mail) writes: : > I'm still digesting the vocabulary thread, but while I do, let me ask a : > question that's probably crystal clear to everyone else. : > : > Do roles act as a form of mix-in, as Ruby modules may, and Objective-C : > protocols do? : > : > Would the following two snippets be at all equivalent? : : Probably, depending on what's in the eventual definition of Foo. : : Roles are quite similar to mixins (as the Traits paper said that they : were inspired by mixins), but they're distinctly not the same. : : For one, one role's methods don't silently override another's. Instead, : you get, er, role conflict and you have to disambiguate yourself. For : two, you can attach new roles to an object at runtime (I don't know if : you can do this with mixins, actually). Yes, you can. The mixin creates a new singleton class every time you do it, derived from the previous class. My current thinking is that run-time roles work a little differently. You get a singleton class for the object the first time you apply a property, so that each object's properties remain distinct. However, subsequent properties re-use the existing singleton class, and do the same role-conflict checks at run time that "does" would do in the class definition at compile time. Furthermore, the singleton class is not really derived from the original class, but just presents a different view of the same class, so that, from the viewpoint of the object, every role has the same standing, and run-time roles aren't privileged above compile-time roles, as they would be if the singleton class were really derived from the original class. In a sense, the object thinks it's recomposing the original class, but it's slightly wrong. If you really want new roles to override old roles, it's easy enough to throw a real derivation in there. But the Traits paper argues, and I'm inclined to agree with them, that this not what you want for the default behavior. Now the Traits paper was really only worrying about composing classes at compile time, and we're extending it to run-time. That means you can get name collisions at run time when you add a role. I still think it's better to catch that sort of goof earlier than later. That means the syntax for C may evolve to look more like the syntax for C. Whatever that looks like... Larry
Re: Vocabulary
On Sat, Dec 13, 2003 at 12:07:40PM -0500, Austin Hastings wrote: : > From: Larry Wall [mailto:[EMAIL PROTECTED] : > The behavior probably doesn't expire unless you've cloned the object : > and the clone expires. However, if a role goes out of its lexical : > scope, it can't be named, so it's effectively not usable unless you : > dig out a name for it via reflection. But the information is still : > cached there, so the object could be smarter the next time it takes : > on the same role. : : It's a role closure, in other words? Erm. That's a fancy word, and I don't claim to know what it means all the time. I suspect the name of the role is closed but the role itself isn't. Alice: "If the name of the role is called Teach..." : That being the case, how to you unapply a role? : : $frank does no Teach; : : $frank doesnt Teach; $frank.role_manager( action => "delete", mode => "override_all_safety_mechanisms", name_the_role_is_called => "Teach" ); Or something like that. :-) : > That being said, a role applied with C probably *should* be : > stripped out when it goes out of scope. Could get messy though... : : I can't think of a way to apply a role with temp (to a non-temp object). How : do you do it? Well, we did set up a way for a method to be temporizable, so it probably comes down to whether C is just syntactic sugar for a method call that knows how to undo itself. Larry
Re: enums and bitenums
On Sat, Dec 13, 2003 at 01:42:58PM +, Andy Wardley wrote: : How about a single colon? : : Color:green Vaguely possible, but the lexer would have to distinguish Color:green Color: green Color :green It may yet do that, but probably not for this reason. : This is the same syntax employed in XML namespaces and URIs, for example: : : http://example.com/xml/color.xsd";> : : : : Don't tell me, we can't use : because we're using that for something : else. :-) Depends on how we treat whitespace, and whether : becomes part of the name. : Presumably, the parser could be smart enough to entuit the : role on either side of a comparison if the other is specified. : :$foo:Color ~~ Color:green : :$foo ~~ Color:green # assumes $foo:Color : :$foo:Color ~~ green # assumes Color:green I want more than that. I want $foo ~~ green to work, provided there's only one definition of "green" in scope. That's why I'd like enums to have a mandatory type, so that they can in fact act like subtypes. : > I'm thinking the ordinary method : > : > $foo.Color : > : > implies : > : > $foo.as(Color) : : What if your $foo object has a regular method called Color? Would it : get called in preference? Following the Traits paper's rule, if the class itself defines a method Color, that takes precedence over any Color methods from roles. But if the class merely inherits a Color method, the role would override the inherited method. That being said, I don't think the situation would arise often in practice if people follow the custom of naming normal methods in lowercase and classes/roles in uppercase. Or we could go the other way, and say that, presuming it's known that Color is a class/role name at compile time, .Color is forced to mean .as(Color) instantly. It could be argued that this doesn't work so well with run-time properties. But you can't name a property unless a declaration is in scope to begin with. Of course, we could also just completely ignore the fact that Color is a class name if there's a dot in front of it, and force everyone to say as(Color) if that's what they mean. That makes the indirect object syntax a little less useful. Instead of $bar = Color $foo: you'd have to say the completely non-English-like $bar = as $foo: Color which is perhaps not a great loss if it encourages people to say $bar = $foo.as(Color) instead. Hmm. Now I'm thinking about the problem of expanding references in list context, since by default a reference doesn't. If you say print $ref it doesn't do what you want, but print $ref.as(Array) might work a lot better, though of course print @$ref does the same thing. But suppose instead of $ref we have a big long expression returning an array reference. Then the .as() form becomes much more readable. So it might well be that all the prefix context operators have .as() counterparts: ~($x) $x.as(Str) ?($x) $x.as(Bit) +($x) $x.as(Num) int($x) $x.as(Int) $($x) $x.as(Scalar) @($x) $x.as(Array) %($x) $x.as(Hash) Though .as() would probably have to be somewhat magical to get the compiler's context analyzer to realize the context of $x in the way that the prefix operators do. (And of course it would have to punt on that analysis if you say $x.as($y) or some such.) Larry
Re: enums and bitenums
On Sat, Dec 13, 2003 at 12:22:00PM -0500, Austin Hastings wrote: : > We might be able to make it work, though as you say, there are other : > ways to get there, and the chances are that at least one of them will : > be a better way. Certainly when the Dog object's class is composed, it : > will have to do something about the conflicting .seeVisitor methods : > in the two roles. : : Hmm. What does that do for run-time behavior? : : If you have to worry about (essentially) every possible role's namespace : conflicting with every other, the whole thing risks getting less useful : quickly. But with the standard approach it merely seems like the whole thing is still useful when in fact your semantics are already clobbered but you just don't know it yet. Better to find out sooner than later. : > It might well be better to encode that choice as : > part of the dog's state rather than in the references to it. : : Treat 'em as a stack. Last one applied dominates. But make sure there's a : way to unstack the roles when finished. Accidental stacks considered harmful. We're trying to get rid of the accidental ones while preserving the ability to have intentional ones. Larry
Re: enums and bitenums
On Sat, Dec 13, 2003 at 07:16:21AM -0800, Paul Hodges wrote: : $Spot = $visitor.nephew ?? $nicedog :: $meandog; : : Which brings up a small side note: that's a successfully applied : boolean context for $visitor.nephew, right? Yes, but $visitor.nephew is no longer .does(nephew) in my current view. You have to say $Spot = $visitor ~~ nephew ?? $nicedog :: $meandog; if nephew is to do any kind of implicit subtype matching. You can also be explicit with .does(), of course. : > : Now, if I'm away and someone show up, I presume that if it's my : > : nephew then $Spot.seeVisitor() will invoke the LapDog role's .wag() : > : method, but otherwise I expect it to invoke the AttackDog role's : > : .Bark() method. I realize there are other ways to get here : > : but would this *work*??? : > : > We might be able to make it work, though as you say, there are other : > ways to get there, and the chances are that at least one of them will : > be a better way. : : lol -- yeah. This is the kind of code I find six months after writing : it and wonder what sort of delerium I was suffering that day. : : So what exactly does it mean to have a "typed reference"? $meandog : still a Dog, just using an AttackDog role, right? So it's type is : Dog&AttackDog? Inheritance thinking starts crowding in here and : blurring my understanding of what's going on. There are going to be some limits on what you can do. We don't have enough parallel universes to allow all uses of all junction types--in the absence of quantum computing the combinatorics are not in our favor... : > Certainly when the Dog object's class is composed, it : > will have to do something about the conflicting .seeVisitor methods : > in the two roles. : : Ah! The class has to reconcile the roles used to build it. : That would cause the same conflict between AttackDog.Bark() and : LapDog.Bark(), if each had one, but that certainly falls back to a : matter of design, and that there are better ways to build it. : : I wish I had generated a better example, but for the sake of : consistency, I'll work with what we've already got, so how about : predefining defaults to resolve known conflicts? : :class Dog does LapDog {...}; :Dog.bark is default(LapDog); # I lowercased .bark() here :class Dog does AttackDog; : :my Dog $Spot = Dog.new(); :$Spot.bark(); # yip, yip :$Spot.AttackDog.bark(); # sick 'em! : : I just noticed I had uppercased my method(s), and it was annoying me. : Anyway, that syntax looks really freaky to me. I can look at it and : know what it was *meant* to do, but how would it be implemented? : : Dog.bark but= LapDog; : : didn't look any better, though. :( : Obviously I'm not awake yet, but maybe these rambles will be useful to : somebody? As a example of the problem with defaults, if nothing else. :-) : > It might well be better to encode that choice as : > part of the dog's state rather than in the references to it. : : I'd say that was almost guaranteed to be the better way to go in : practice. I've just seen too many cases where I was handed poorly : designed legacy code and expected to hack it into some new : functionality, "oh and we need that by three today?" : : My workplace considers refactoring to be reinventing the wheel. Just : add another motor and axle over here!! sheesh, lol With multis you can be refactoring while you're also adding motors and axles. :-) : > On the other hand, it might just fall out of our implementation : > that it does the right thing with typed references, if the method : > dispatch to the conflicting methods in the Dog class can have access : > to the reference types to break ties. : : And since the type of the ref could be Dog&LapDog&AttackDog&Pet, that : should work. :) Touché. Larry
Re: Vocabulary
On Sat, Dec 13, 2003 at 12:50:50PM -0500, Austin Hastings wrote: : > -Original Message- : > From: Larry Wall [mailto:[EMAIL PROTECTED] : > Sent: Friday, December 12, 2003 8:30 PM : : > On Fri, Dec 12, 2003 at 05:17:37PM -0500, Austin Hastings wrote: : > : I presume that the linear order (compile time) or chronological order of : > : applying roles decides the order in which overlaid methods are : > : Ced/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. : : I'm not convinced these are errors. Having a role override methods makes : sense in a lot of ways. A role method certainly overrides inherited methods, so it's only methods defined in the class itself we're talking about here. : Consider, for example, a caching or persistence implementation that : overrides the .STORE method of its victims. I think the class is still the final arbiter of what its objects are--there is no other entity that holds all the reins. If a class chooses to include a role, and that role violates the normal rules of roles, the class is still responsible for that (or else you need some babysitting code somewhere, hopefully in the metaclass). Maybe that's what a trait is--a renegade role. Instead of does Storable maybe it's is storable : It seems to me there's an argument both ways -- : : 1. Code written in the absence of a role won't anticipate the role and : therefore won't take (unknowable) steps to disambiguate method calls. Ergo : method overloads are bad. : : 2. Roles may be written to deliberately supercede the methods of their : victims. Method overloads are vital. I think the default has to be 1, with an explicit way to get 2, preferably with the agreement of the class in question, though that's not absolutely necessary if you believe in AOP. : This doesn't take into account role vs. role conflicts (which seem more : likely to be serendipitous). : : Perhaps an "exact signature" rule would work? Such that if the method was an : exact replacement, then no error occurs, otherwise it becomes either an : error or a multi? Er, which method? : Alternatively, perhaps a role must declare its method to be multi or not, : and if not then the role's method overloads the original class's. No, I think the default needs to be such that the class's method is expected to dispatch to the role's method. If no such method exists then it falls back on the normal role method dispatch. In either case, it would almost always be the case that you'd want multimethod dispatch to the set of role methods of the same name. I'm starting to think that any methods declared in roles are automatically considered "multi" when composed, whether so declared or not. : (Which takes us to retroactive multi-fication. Ugh.) More like proactive multi-fication, I think. : Or perhaps you just have to say "this method overloads". If it's part of the role contract, it's part of the contract. But maybe that makes it a trait. : > 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. : : At compile time, right? Whereas composition (but=) overrides declaration at : run-time? I don't think the rules for run-time roles should be different than the rules for compile-time roles (because Perl doesn't make a hard-and-fast distinction between compile time and run time). And the arbitration logic has to be somehow associated with the class, either explicitly by the class's declarations, or by some babysitting code telling the class how to behave given the new composition. I've been talking about singleton classes to implement run-time roles, but that's not quite right. I think a class caches its various compositions and either reuses an existing one or creates a new composition depending on which set of roles has been bound to the current object. It might seem like you could have a combinatorial explosion of the possible number of compositions if multiple properties are applied at run time, but when you think about, the number of those cached compositions has to be equal or less than the number of singleton classes you'd get if you created a new one for every object with one or more properties. In general there will be many fewer compositions than singletons. So whenever you bind a run-time role, the class looks to see if it already knows how to do the combination of roles this object wants, and if so, the role binding is very fast. Otherwise it creates the new composition, checks for conflicts, resolves them (or doesn't), and then binds the new composition as the object's current view of its class. In a
splatting a reference
On Sat, Dec 13, 2003 at 12:12:59PM -0800, Larry Wall wrote: > > print $ref > > it doesn't do what you want, but > > print $ref.as(Array) > > might work a lot better, though of course > > print @$ref > What is supposed to do the splat operator in this context? My understanding is that when an operator expects something and gets a ref instead, the ref is dereferenced until the expected operand is found. The interpretor barks otherwise. So I expect print *$ref when $ref is ref to an array to be equivalent to print [EMAIL PROTECTED] which in turn should behave like print @$ref because C splats its operands. I don't pretend that C is very readable, I just ask what it does or if it is at all permitted. -- stef
Re: enums and bitenums
--- Larry Wall <[EMAIL PROTECTED]> wrote: > On Sat, Dec 13, 2003 at 07:16:21AM -0800, Paul Hodges wrote: > : $Spot = $visitor.nephew ?? $nicedog :: $meandog; > : > : Which brings up a small side note: that's a successfully applied > : boolean context for $visitor.nephew, right? > > Yes, but $visitor.nephew is no longer .does(nephew) in my current > view. You have to say > > $Spot = $visitor ~~ nephew ?? $nicedog :: $meandog; > > if nephew is to do any kind of implicit subtype matching. You can > also be explicit with .does(), of course. I knew that, lol -- but again, that's why I lurk here. I'm trying keep my habits chasing the curve of whatever's being worked out. > : So what exactly does it mean to have a "typed reference"? $meandog > : still a Dog, just using an AttackDog role, right? So it's type is > : Dog&AttackDog? Inheritance thinking starts crowding in here and > : blurring my understanding of what's going on. > > There are going to be some limits on what you can do. We don't have > enough parallel universes to allow all uses of all junction types--in > the absence of quantum computing the combinatorics are not in our > favor... Amen, brutha. Accordingly, do we have an idea what it actually means to add a type to something? I mean, I get that we could say print "yup" if $Spot ~~ AttackDog; but is there still print ref $Spot; and if so what does it print??? > : Obviously I'm not awake yet, but maybe these rambles will be useful > : to somebody? > > As a example of the problem with defaults, if nothing else. :-) lol -- hey, if I can be a bad example, at least my life has *some* purpose. :) > : My workplace considers refactoring to be reinventing the wheel. > : Just add another motor and axle over here!! sheesh, lol > > With multis you can be refactoring while you're also adding motors > and axles. :-) oooOoohh.. Hey! I *LOVE* that! >:op __ Do you Yahoo!? New Yahoo! Photos - easier uploading and sharing. http://photos.yahoo.com/
Re: enums and bitenums
On Sat, Dec 13, 2003 at 03:43:00PM -0800, Paul Hodges wrote: : Amen, brutha. Accordingly, do we have an idea what it actually means to : add a type to something? I mean, I get that we could say : : print "yup" if $Spot ~~ AttackDog; : : but is there still : : print ref $Spot; : : and if so what does it print??? It still prints Dog. The current composition of the Dog class for this object is largely anonymous. If it has a name, it's something like %Dog::__COMPOSITION__{AttackDog & Pet}. But every dog thinks its a Dog. Larry
Re: splatting a reference
On Sat, Dec 13, 2003 at 11:04:57PM +0100, Stéphane Payrard wrote: : On Sat, Dec 13, 2003 at 12:12:59PM -0800, Larry Wall wrote: : > : > print $ref : > : > it doesn't do what you want, but : > : > print $ref.as(Array) : > : > might work a lot better, though of course : > : > print @$ref : > : : What is supposed to do the splat operator in this context? Splat is a no-op in list context. Its only use in an rvalue is to introduce a list context where scalar context would normally be inferred. So you could say @args = ([EMAIL PROTECTED], 1, 2, 3); push [EMAIL PROTECTED]; even though push expects a scalar array ref as the first argument. : My understanding is that when an operator expects something and gets : a ref instead, the ref is dereferenced until the expected operand : is found. The interpretor barks otherwise. In scalar context, that's basically true. (All ordinary scalars are references anyway, which is why @_ is a call-by-reference array.) In list context, however, a scalar variable provides a scalar value by default. It could be a scalar reference to the entire OED, but Perl thinks it's a singular value, not a plural one, unless you tell it otherwise somehow. Actually, C was a bad example, because $ref might well be expanded (in a sense) by the stringification implicit to print. Instead, let's consider: push @array, $ref; That pushes a single reference into the array, because that is what it looks like it's doing. If you say push @array, $a, $b; it doesn't matter whether $a or $b are references to arrays--it still only pushes two singular values into the array. In this case you would have to say push @array, @$a, @$b; to get the arrays flattened into the push's list argument. (This is just how it works in Perl 5 too.) It would be possible to make the default the other way, and explicitly mark where you *don't* want expansion, but I think it would be much more error prone. It would certainly make it more difficult to read unfamiliar code and figure out what's going on. : So I expect : : print *$ref : : when $ref is ref to an array to be equivalent to : : print [EMAIL PROTECTED] : : which in turn should behave like : : print @$ref : : because C splats its operands. : : I don't pretend that C is very readable, I just ask : what it does or if it is at all permitted. It's permitted, but does nothing. I admit that, to a C programmer, it looks a bit like a deref, but this isn't C. Perl has always derefed arrays and hashes with @ and %, and that doesn't change in Perl 6. All I'm saying above is that .as(Array) and .as(Hash) might have the same result of explicitly dereferencing a singular reference to a plural value. Larry