Re: Role Method Conflicts and Disambiguation
On Fri, Oct 28, 2005 at 14:04:35 -0500, Jonathan Scott Duff wrote: > That there will not be two slots for $:foo in Xy, but only one. > > But, I'm probably wrong about this as the X role may have methods that > use $:foo in one way and the Y role may have methods that use $:foo in > some other, incompatible way, so perhaps there will be a conflict just > as when there are 2 methods of the same name. Uh, that's horrible, because it means private attributes have only the disadvantages of privacy (no access) and not the advantages (separation, no conflicts). non-private attributes should conflict, but private attributes are no one's business except the package which made them. -- () Yuval Kogman <[EMAIL PROTECTED]> 0xEBD27418 perl hacker & /\ kung foo master: uhm, no, I think I'll sit this one out..: neeyah! pgpGGuBWg08p4.pgp Description: PGP signature
Re: Why submethods
Luke, On Oct 29, 2005, at 3:42 PM, Luke Palmer wrote: Another thing that scares me with the "utility sub" point of view follows: class Foo { method process_data($data) { $.help_process_data($data); } submethod help_process_data($data) { $data+1; } } Foo.new.process_data(0); # 1 class Bar is Foo { } Bar.new.process_data(0); # dies[1] What??? I didn't change anything yet! Why does it die? (This is the first principle in the journal entry you quoted) This is true, but I think that it is easily rectified. A submethod is said to have an implicit next METHOD unless $?SELF.class =:= $?CLASS I think we could add onto that and say that in addition to checking the invocant's class, we could also check the calling context, and do like we do with private methods, and allow things like this to Just Work. However, it could also be that the creator of Foo did not intend for subclasses to be able to "Just Work", and that the whole idea of Foo is to do a "Template Method" style pattern in which subclasses must implement the &help_process_data submethod in order for things to work. This is an entirely valid usage for a submethod, and in fact, I think it is an excellent way for implementing the "Template Method" pattern. It is also possible that we could bring over the role idea of "required methods" and have the same basic principle relate to classes and submethods. If marked as such, a submethod is required to be implemented by a subclass, or class composition fails. I think that could be a useful feature which would allow very safe re-use along those lines. Anyway, just my 2 cents. Stevan
Re: Why submethods
On 10/29/05, Damian Conway <[EMAIL PROTECTED]> wrote: > So we need a mechanism that is externally (i.e. from a class interface > point-of-view) a subroutine, but internally has the features of a method (i.e. > has an invocant). Since it's externally sub-like but internally method-like, > we call this useful construct a submethod. Hmm, thanks. For most of that, doesn't a private method suffice? When it doesn't, I feel uneasy about: class Foo { submethod bar() { ... } } my $foo = Foo.new; $foo.bar; If that's externally sub-like, why does it look so much like a method? Another thing that scares me with the "utility sub" point of view follows: class Foo { method process_data($data) { $.help_process_data($data); } submethod help_process_data($data) { $data+1; } } Foo.new.process_data(0); # 1 class Bar is Foo { } Bar.new.process_data(0); # dies[1] What??? I didn't change anything yet! Why does it die? (This is the first principle in the journal entry you quoted) Let's presume that I want to extend Foo by adding a method completely unrelated to process_data, and I would like its behavior to stay the same for process_data. How would I do that? Luke [1] Well, it wouldn't, since for Liskov sanity we require that a method of the same name already exists. Let's say that Foo's parent class implemented "submethod help_process_data($data) { die }".
Re: should roles be parameterized?
On 10/28/05, Christopher D. Malon <[EMAIL PROTECTED]> wrote: > On Oct 28, 2005, at 11:13 PM, Luke Palmer wrote: > Trying to think through the VectorSpace example, and a slightly > more complicated example (a Field), I'm starting to wonder whether > roles need to be parameterized somehow. (Maybe they already are? > This is one of my first p6 attempts, so bear with me...) Oh yeah, roles can be parameterized. role VectorSpace[Field ^f] {...} role Field[AbelianGroup ^plus, Group ^times] {...} I'm intentionally handwaving over some details that are important. See below. > role Group should define a method "inverse()" whose implementation > is up to the class. inverse(operation => '+') or inverse(operation > => '*') > would make perfect sense. On an object that does Group only one way, > inverse() by itself would be okay, but it would be ambiguous > on a Field object. I don't know whether it's better for the interpreter > to produce a run-time error when a class implements a role in two ways > and the parameter isn't supplied, or if one implementation of a role > should > take priority. This is indeed the problem. A related problem is, let's say you have a utility sub for groups: # Group $x meaining an element of a group... that's a little strange sub power(Group $x, Int $pow) { given $pow { when $_ < 0 { power(inverse($x), -$pow) } when $_ == 0 { identity() } when $_ > 0 { $x * power($x, $pow - 1) } } } But what if you have a set that is a group under addition? That doesn't work, since you're trying to multiply here. sub power(Group[&infix:<*>] $x, Int $pow) { # same body as before } That assumes that Group has one parameter: the operation under which it is a group. Then you *bind* that parameter to a lexical infix:<*>, which means that when you say * within the body of your subroutine, you actually mean whatever operation the group defines. However, we still have a problem when we give a Field to power. Which group do we mean? One way to do this would be to pass an optional parameter: an object describing the group: sub power(Group $x, Int $pow, GroupDesc $desc = $x.desc) { given $pow { when $_ < 0 { power($desc.inverse($x), -$pow, $desc) } when $_ == 0 { $desc.identity } when $_ > 0 { $x * $desc.power($x, $pow - 1, $desc) } } } But that's starting to take away from the readability of the code, and it really takes away from the fact that Group is encoding the structure. There was a proposal in Haskell to have what they called "named instances", which addresses these kinds of problems: http://www.informatik.uni-bonn.de/~ralf/hw2001/4.pdf Perlizing the proposal, we might have something like: role Field[&infix:<+>, &infix:<*>] { does Group[&infix:<+>] FieldPlus; does Group[&infix:<*>] FieldTimes; ... } power(4, 3) (FieldPlus); # 12 power(4, 3) (FieldTimes); # 256 All group operations on a field would be on the Plus group if we're in a FieldPlus context, and conversely, all group operations on the field would be on the Times group if we're in a FieldTimes context. Exploring this issue further could be important to Perl's power when it comes to automatic dispatch. Luke
Why submethods
In his use.perl.org journal, Luke wrote: > To be fair, Damian responded to my query, but he didn't answer my > question. He gave more an example of how submethods are used, rather > than why they are used. Subroutines are useful inside classes, for factoring class-specific implementation details out of the class's methods. The main reason they're useful is because they're not part of the object interface, and are not inherited. So they can be used purely for encapsulated implementation. But factoring method implementations out into a subroutines is also extremely annoying, because a subroutine doesn't provide the internal conveniences that a method does. In particular, it doesn't have an invocant and so you can't call $.attrs or &.methods. Instead you would have to pass the invocant to the subroutine call as an argument and then call accessors and methods explicitly through that argument. So we need a mechanism that is externally (i.e. from a class interface point-of-view) a subroutine, but internally has the features of a method (i.e. has an invocant). Since it's externally sub-like but internally method-like, we call this useful construct a submethod. Damian