Re: This week's summary
Uri Guttman wrote: i say we just sell them a license to use the US constitution. Bill Gates wrote: What is it with these Linux guys? i say we just sell them a license to use Windoze. :-) A
RE: This week's summary
In article [EMAIL PROTECTED], [EMAIL PROTECTED] (Austin Hastings) writes: PS: While I'm somewhat sympathetic to the fact that eu guys are trying to spin up 200 years worth of amendments and supreme court decisions at the same time, it's still a ratf*ck. Eu need to get eurselves a Larry. Just put Damian on it, and there'll be a Lingua::EU::ConstitutionGenerator by Christmas. Probably with a back door making him king with droit du seigneur option in perpetuity. -- Peter Scott http://www.perldebugged.com/ *** NEW *** http//www.perlmedic.com/
Re: Roles and Mix-ins?
- Original Message - From: Luke Palmer [EMAIL PROTECTED] To: [EMAIL PROTECTED] Sent: Tuesday, January 06, 2004 4:51 AM Subject: [perl] Re: Roles and Mix-ins? David Storrs writes: On Sat, Dec 13, 2003 at 11:12:31AM -0800, Larry Wall wrote: On Sat, Dec 13, 2003 at 04:57:17AM -0700, Luke Palmer wrote: : For one, one role's methods don't silently override another's. Instead, : you get, er, role conflict and you have to disambiguate yourself. How do you disambiguate? Let's see... role Dog { method bark() { print Ruff! } } role Tree { method bark() { print Rough! } } class Trog does Dog does Tree { method bark() { .Dog::bark() } } } Perhaps something like that. In any case, you do it by putting the offending method directly in the aggregating class. How about something like class Trog does Dog {bark=dogBark} does Tree {bark=treeBark} {...} Then we could have code like my Trog $foo = Trog.new(); my Dog $spot := $foo; my Tree $willow := $foo; $spot.bark(); # calls dogBark() $willow.bark(); #calls treeBark() This works better when Dog::bark and Tree::bark are both needed but they do different things. Joe Gottman
Re: Roles and Mix-ins?
Joe Gottman writes: - Original Message - From: Luke Palmer [EMAIL PROTECTED] To: [EMAIL PROTECTED] Sent: Tuesday, January 06, 2004 4:51 AM Subject: [perl] Re: Roles and Mix-ins? David Storrs writes: On Sat, Dec 13, 2003 at 11:12:31AM -0800, Larry Wall wrote: On Sat, Dec 13, 2003 at 04:57:17AM -0700, Luke Palmer wrote: : For one, one role's methods don't silently override another's. Instead, : you get, er, role conflict and you have to disambiguate yourself. How do you disambiguate? Let's see... role Dog { method bark() { print Ruff! } } role Tree { method bark() { print Rough! } } class Trog does Dog does Tree { method bark() { .Dog::bark() } } } Perhaps something like that. In any case, you do it by putting the offending method directly in the aggregating class. How about something like class Trog does Dog {bark=dogBark} does Tree {bark=treeBark} {...} Then we could have code like my Trog $foo = Trog.new(); my Dog $spot := $foo; my Tree $willow := $foo; $spot.bark(); # calls dogBark() $willow.bark(); #calls treeBark() This works better when Dog::bark and Tree::bark are both needed but they do different things. Renaming methods defeats the purpose of roles. Roles are like interfaces inside-out. They guarantee a set of methods -- an interface -- except they provide the implementation to (in terms of other, required methods). Renaming the method destroys the interface compatibility. Your renaming can be done easily enough, and more clearly (IMO) with: class Trog does Dog does Tree { method bark() { ... } # Explicitly remove the provided method method dogBark() { .Dog::bark() } method treeBark() { .Tree::bark() } } Luke
Re: Roles and Mix-ins?
Joe Gottman wrote: How about something like class Trog does Dog {bark=dogBark} does Tree {bark=treeBark} {...} Then we could have code like my Trog $foo = Trog.new(); my Dog $spot := $foo; my Tree $willow := $foo; $spot.bark(); # calls dogBark() $willow.bark(); #calls treeBark() This works better when Dog::bark and Tree::bark are both needed but they do different things. I'm not sure about the syntax, but it does a great job of illustrating the aliasing approach to disambiguation. The exclusion approach might be something like: class Trog does Dog does Tree but no bark {...} so that, as far as class Trog is concerned, there Iis no bark method for Tree. That is, include a pair of traits[1]: no and alias, where no modifies the class to remove the specified attributes and/or methods, and where alias modifies the class to rename the specified attribute or method; then apply those traits to the roles in question as if they were properties[2], creating singleton roles that are used to compose the class. This would require but to have a higher precedence than is or does, but I think that that might actually make sense. The only drawback to this is that I don't see the no and alias traits being useful except as properties: you exclude a method from a class simply by not defining it in the first place; and if you want to use a different name for a given method, you simply use the different name for it. Then again, you could probably use no to implement something akin to C++'s private, where the method excluded by no is merely excluded from use outside the class, while other class methods could see and use it normally. I suppose that a similar line of reasoning would technically apply to alias; but it's beyond my ability to see how forcing a method to be known by a different name by non-class methods than it is by class methods could possibly be useful. Meanwhile, Luke was essentially pointing out that class methods take precedence over role methods, and role methods Ican be accessed by explicitly specifying which role to use; so specifying a class method with the same name as ambiguous role methods but which explicitly calls one of them would also remove the ambiguity. [1] by trait, I'm referring to a thing (which might or might not be like a role but probably isn't) which is applied to a class via Cis and which modifies the standard rules for how the class behaves. The more I look at traits, the more I'm seeing them as being more sub-like than role-like: they're defined more in terms of what they do to the class than what they provide to the class. [2] by property, I'm referring to a role that is applied to a class via Cbut, resulting in a new singleton class that Cis the original class and Cdoes the new role. This differs from previous (and currently official) use of the term in that I do Inot assume that the role in question has exactly one attribute. If someone can come up with a better term for something like an official property, but more general, I'd be more than happy to adopt its use instead. = Jonathan Dataweaver Lang __ Do you Yahoo!? Yahoo! Hotjobs: Enter the Signing Bonus Sweepstakes http://hotjobs.sweepstakes.yahoo.com/signingbonus
Re: Roles and Mix-ins?
Luke Palmer wrote: Renaming methods defeats the purpose of roles. Roles are like interfaces inside-out. They guarantee a set of methods -- an interface -- except they provide the implementation to (in terms of other, required methods). Renaming the method destroys the interface compatibility. Not so. A role is more than an inside-out interface; it guarantees a set of methods either by calling it an error to not define a given method in a class that Cdoes the role or by defining the method itself. In the latter case, renaming the method can be quite useful; even in the former case, renaming or excluding methods from a role is useful if you want an interface which is almost, but not quite, like the one that the role provides. = Jonathan Dataweaver Lang __ Do you Yahoo!? Yahoo! Hotjobs: Enter the Signing Bonus Sweepstakes http://hotjobs.sweepstakes.yahoo.com/signingbonus
Re: Roles and Mix-ins?
- Original Message - From: Luke Palmer [EMAIL PROTECTED] To: Joe Gottman [EMAIL PROTECTED] Cc: Perl6 [EMAIL PROTECTED] Sent: Tuesday, January 06, 2004 9:34 PM Subject: [perl] Re: Roles and Mix-ins? Joe Gottman writes: - Original Message - From: Luke Palmer [EMAIL PROTECTED] To: [EMAIL PROTECTED] Sent: Tuesday, January 06, 2004 4:51 AM Subject: [perl] Re: Roles and Mix-ins? David Storrs writes: On Sat, Dec 13, 2003 at 11:12:31AM -0800, Larry Wall wrote: On Sat, Dec 13, 2003 at 04:57:17AM -0700, Luke Palmer wrote: : For one, one role's methods don't silently override another's. Instead, : you get, er, role conflict and you have to disambiguate yourself. How do you disambiguate? Let's see... role Dog { method bark() { print Ruff! } } role Tree { method bark() { print Rough! } } class Trog does Dog does Tree { method bark() { .Dog::bark() } } } Perhaps something like that. In any case, you do it by putting the offending method directly in the aggregating class. How about something like class Trog does Dog {bark=dogBark} does Tree {bark=treeBark} {...} Then we could have code like my Trog $foo = Trog.new(); my Dog $spot := $foo; my Tree $willow := $foo; $spot.bark(); # calls dogBark() $willow.bark(); #calls treeBark() This works better when Dog::bark and Tree::bark are both needed but they do different things. Renaming methods defeats the purpose of roles. Roles are like interfaces inside-out. They guarantee a set of methods -- an interface -- except they provide the implementation to (in terms of other, required methods). Renaming the method destroys the interface compatibility. Your renaming can be done easily enough, and more clearly (IMO) with: class Trog does Dog does Tree { method bark() { ... } # Explicitly remove the provided method method dogBark() { .Dog::bark() } method treeBark() { .Tree::bark() } } But won't explicitly removing bark() from the class also disable Dog::bark() and Tree::bark() for the class? Renaming would work if other methods in Dog are directed to dogBark() when they call bark(), and other methods in Tree are redirected to treeBark(). Joe Gottman
RE: Roles and Mix-ins?
From: Jonathan Lang [mailto:[EMAIL PROTECTED] Luke Palmer wrote: Renaming methods defeats the purpose of roles. Roles are like interfaces inside-out. They guarantee a set of methods -- an interface -- except they provide the implementation to (in terms of other, required methods). Renaming the method destroys the interface compatibility. Not so. A role is more than an inside-out interface; it guarantees a set of methods either by calling it an error to not define a given method in a class that Cdoes the role or by defining the method itself. In the latter case, renaming the method can be quite useful; even in the former case, renaming or excluding methods from a role is useful if you want an interface which is almost, but not quite, like the one that the role provides. There's two ways to look at that. One way is to say: I'm going to define an interface as being this OTHER thing minus a method. That seems like a positive construction, and supporting it might be desirable. The other way is to say: Nobody knows what methods call what other methods in their implementation (nor should we know). Therefore, removing methods is forbidden. If you have a conflict of methods, alias them and provide support in the knowledge that any component Crole that requires the method may call it internally. I'm in favor of the second approach, myself. If you alias away all of the (e.g.) Cbark methods, you must provide a replacement. =Austin
Re: Roles and Mix-ins?
Joe Gottman wrote: Luke Palmer wrote: Your renaming can be done easily enough, and more clearly (IMO) with: class Trog does Dog does Tree { method bark() { ... } # Explicitly remove the provided method method dogBark() { .Dog::bark() } method treeBark() { .Tree::bark() } } But won't explicitly removing bark() from the class also disable Dog::bark() and Tree::bark() for the class? No. method bark isn't technically being removed; rather, method Trog::bark is being defined as postpone the definition while simultaneously taking precedence over both Dog::bark and Tree::bark, since it is a class method native to Trog while the others are role methods provided to Trog - and class methods take precedence over role methods. So if my Trog $spot; $spot.bark; is executed, perl will unambiguously call $spot.Trog::bark, and then complain that it hasn't been defined. (This assumes that it doesn't complain during compile-time.) This works, but seems counterintuitive to me. = Jonathan Dataweaver Lang __ Do you Yahoo!? Yahoo! Hotjobs: Enter the Signing Bonus Sweepstakes http://hotjobs.sweepstakes.yahoo.com/signingbonus
RE: Roles and Mix-ins?
Austin Hastings wrote: There's two ways to look at that. One way is to say: I'm going to define an interface as being this OTHER thing minus a method. That seems like a positive construction, and supporting it might be desirable. The other way is to say: Nobody knows what methods call what other methods in their implementation (nor should we know). Therefore, removing methods is forbidden. If you have a conflict of methods, alias them and provide support in the knowledge that any component Crole that requires the method may call it internally. Or you could say that when you exclude a method, what you're really doing is hiding it from everything external to where it's declared, while leaving it available to be called internally. Method exclusion would be more like declaring a private method in C++ than actually removing it from the class or role. This means that a method wouldn't be provided to a class that Cdoes its role but excludes it itself, and thus it wouldn't be used to satisfy the requirements of any other roles that the class Cdoes. = Jonathan Dataweaver Lang __ Do you Yahoo!? Yahoo! Hotjobs: Enter the Signing Bonus Sweepstakes http://hotjobs.sweepstakes.yahoo.com/signingbonus
RE: Roles and Mix-ins?
From: Jonathan Lang [mailto:[EMAIL PROTECTED] Austin Hastings wrote: There's two ways to look at that. One way is to say: I'm going to define an interface as being this OTHER thing minus a method. That seems like a positive construction, and supporting it might be desirable. The other way is to say: Nobody knows what methods call what other methods in their implementation (nor should we know). Therefore, removing methods is forbidden. If you have a conflict of methods, alias them and provide support in the knowledge that any component Crole that requires the method may call it internally. Or you could say that when you exclude a method, what you're really doing is hiding it from everything external to where it's declared, while leaving it available to be called internally. Method exclusion would be more like declaring a private method in C++ than actually removing it from the class or role. This means that a method wouldn't be provided to a class that Cdoes its role but excludes it itself, and thus it wouldn't be used to satisfy the requirements of any other roles that the class Cdoes. Huh? If it's available to be called internally, you've got the same problem (we were talking about conflict resolution earlier, I think) -- that you need to know which one to call. So you alias one (Dog::bark) to dogBark, which leaves Tree::bark as the default bark. This is fine. But if you say there ain't no bark, either we should complain that doing a Dog or a Tree demands it, or we should catch the exception at compile or run time. I'm in favor of the first solution -- you must provide one -- since that seems to be more in keeping with the general role philosophy that Larry's been emitting. The notion of I'm defining it to be {...} is an interesting one -- you're explicitly discussing it, so obviously you've thought about it. But it's not there. I wonder if it wouldn't be easier to say {fail} instead? =Austin
A modest question
Larry, chromatic, Allison, Damian, et al: What's the big fascination with traits? I read the paper, and at the end where they talked about refactoring the Smalltalk class library, they managed to claim 12% fewer lines of code: In total, these classes use 46 different traits and implement 509 methods, whereof 36 are automatically generated accessor methods. This is just over 5% fewer methods than in the original implementation. In addition, the code for the trait implementation is 12% smaller than the original. However, the authors continue to report: This is especially remarkable because 10% of the methods in the original implementation are implemented too high in the hierarchy specifically to enable code sharing. With inheritance, the penalty for this is the repeated need to cancel inherited behaviour (using methods that cause a runtime error) in subclasses where they do not make sense. In the trait implementation, there is no need to resort to this tactic. Which I interpret as meaning that the artificially high code-sharing implementations have caused extra lines of code in lower level classes. So the 12% figure is inclusive of deliberate pessimization that has been done to substitute clarity for compactness -- presumably native code that hasn't been evolved so much would have more compactness, less redundant code, and would yield less than 12% improvement by refactoring into the traits model. So on the grand balance of utility, what are the metrics that traits are supposed to help improve? The 10% reduction of LOC reminds me of the old Assembler rule of thumb: do it last, you'll get 10% faster. Presumably there are some other metrics being improved. Can one or more of you explain what the perceived improvements, and what's the order of significance? That is, give us a 1. 2. 3. list? Thanks, =Austin
Re: A modest question
On Tue, 2004-01-06 at 22:26, Austin Hastings wrote: So on the grand balance of utility, what are the metrics that traits are supposed to help improve? Two big ones: - naming collections of behavior that are too fine-grained to fit into classes cleanly - enabling finer-grained code reuse Consider a method that needs to print an object. You might require a String: sub print_it ( String $thingie ) { print $thingie; } Why does it have to be a String, though? What prevents it from working with anything that can stringify, besides the overly restrictive signature? What if you could say (the Perl 6 equivalent of): sub print_it ( does Stringify $thingie ) { print $thingie.stringify(); } That's both more general and something more specific. By asking for what you really want, you're not coding everyone else into a corner. Take Mail::SimpleList and Mail::TempAddress, for example. Both have classes that represent individual addresses or mailing lists. The appropriate parent class is Mail::Action::Address, which has the very basic data and properties that both subclasses share. Both simple lists and temp addresses should contain expiration dates, so both classes need some sort of behavior to implement that. When you throw another class into the mix, say, Mail::OneWayList, where there's no expiration (trust me, even though it's not on the CPAN yet), there's a problem. I'd like to share code between all three classes that represent aliases and Mail::Action::Address is the appropriate place to do that. I don't want to share *all* of the code, though, so I can't really put the expiration code in Mail::Action::Address. I *could* subclass Mail::Action::Address and make Mail::Action::Address::Expires and change the parent class of the temp address and the simple list classes, but that's kinda icky as it leads to yet another level in the class hierarchy. By turning expiration into a role, though, everything can extend Mail::Action::Address and only those classes that really need expiration can do it -- and they share the code. Contrived example? Maybe. Maybe not. Consider further James Fitzgibbon's Mail::Action::Role::Purge. James wanted to extend all Mail::Action subclasses to allow purging of expired addresses or lists. That's reasonable, but it's not something I wanted to add to Mail::Action because it doesn't know anything about expiration. So he made it a role and decorates expirable objects with the role and can do what he wants there. Again, the goals are specificity, genericity, and improved reuse. -- c