Re: subclassing associated classes elegantly
On 10/19/05, Stevan Little <[EMAIL PROTECTED]> wrote: > Darren, > > Your problem reminds me of the "Expression Problem", which is > something that IIRC Luke's Theory idea was trying to solve. Indeed, this problem is almost exactly the contravariant half of the expression problem. Once upon a time, a theory was supposed to represent your "role AB", but it has diverged from that. Nowadays I think a problem like this solved by deriving from a module, which isn't too unlike what you were showing. The "factory" abstraction from the theory proposal solves the well-typedness of this kind of solution. Here's a guess: module AB; class A { submethod one () { return 'hello'; } submethod two () { B.four(); } } class B { submethod three () { A.one(); } submethod four () { return 'here'; } } module CD; is AB; class A is AB::A { submethod one () { return 'world'; } } class B is AB::B { submethod four () { return 'there'; } } This is treating all names in a module as virtual. There may be a downside to this, in which case we could go Scala's direction and make the distinguishing property of a role (there called "trait") that the things it declares are virtual. However, if you're ever deriving from a module, a somewhat uncommon thing to do, supposedly you're doing so precisely to make the names virtual like this. So this may just be the right solution. Luke
Re: subclassing associated classes elegantly
On 10/19/05, Darren Duncan <[EMAIL PROTECTED]> wrote: [snip] > An example of when this situation can arise is if person X implements > a simplified XML DOM implementation using 2 classes, Document and > Node, that work together, where one of those classes (Document) can > create objects of the other (Node), and person Y wants to subclass > the XML DOM implementation, meaning that those same Node objects made > by one of person Y's Document subclass should be objects of person > Y's Node subclass. > > To illustrate, say we had these 4 classes (the syntax may be wrong): > ># This is one associated class set: > >class A { > submethod one () { >return 'hello'; > } > > submethod two () { >B.four(); > } >} > >class B { > submethod three () { >A.one(); > } > > submethod four () { >return 'here'; > } >} > ># This is separate and optional associated class set: > >class C is A { > submethod one () { >return 'world'; > } >} > >class D is B { > submethod four () { >return 'there'; > } >} > > What I want to be able to do is set things up so that user code can > do something that is effectively like this: > >my $first = A.two(); # returns 'here' >my $second = B.three(); # returns 'hello' >my $first = C.two(); # returns 'there' >my $second = D.three(); # returns 'world' > > The situation is that classes C and D represent any arbitrary named 2 > classes that are subclassed from A and B, and so the latter can't > know the names of the former, and the latter have to work > independently of C and D also. > > This is one variant of a solution I have come up with: > ># This is one associated class set: > >role AB { > submethod name_of_class_A () { >return 'A'; > } > > submethod name_of_class_B () { >return 'B'; > } >} > >class A does AB { > submethod one () { >return 'hello'; > } > > submethod two () { >.name_of_class_B().four(); > } >} > >class B does AB { > submethod three () { >.name_of_class_A().one(); > } > > submethod four () { >return 'here'; > } >} > ># This is separate and optional associated class set: > >role CD { > submethod name_of_class_A () { >return 'C'; > } > > submethod name_of_class_B () { >return 'D'; > } >} > >class C is A does CD { > submethod one () { >return 'world'; > } >} > >class D is B does CD { > submethod four () { >return 'there'; > } >} > > This is another variant of a solution I have come up with: > ># This is one associated class set: > >role AB { > submethod invoke_one () { >return A.one(); > } > > submethod invoke_four () { >return B.four(); > } >} > >class A does AB { > submethod one () { >return 'hello'; > } > > submethod two () { >.invoke_four(); > } >} > >class B does AB { > submethod three () { >.invoke_one(); > } > > submethod four () { >return 'here'; > } >} > ># This is separate and optional associated class set: > >role CD { > submethod invoke_one () { >return C.one(); > } > > submethod invoke_four () { >return D.four(); > } >} > >class C is A does CD { > submethod one () { >return 'world'; > } >} > >class D is B does CD { > submethod four () { >return 'there'; > } >} > > In either case, the expectation here is that the submethods of role > CD will override those of role BC regardless of which class' other > methods invoke those, when the invocant class is C or D. > > So I'm wondering what is the best way to develop my associated class > sets such that it is easiest for third parties to be able to > subclass-extend them. Should I use one of the two solutions above > (both of which have been tried in real life, in Perl 5, the second > more recently)? Or is there another solution that is better than > both? > > Also, in such a situation as the above, is it reasonable to support > easy subclassing, or would it be better to avoid that complexity and > instead expect users to create objects that wrap the others instead > of subclassing them? > > Assume also that it may be counter-productive for one class to expect > user code to invoke the second class on its behalf, such as if when > pair of classes is hidden behind a second pair of classes that > mediate access to them. > > What are some best practices here that can be used by anyone faced by > a similar problem? > > -- Darren Duncan > [snip] In Perl5, I would think the easiest solution would be to "trick" the base Document class into using the right Node class. 1) Load Node. 2) Rename Node to Node::Base 3)
Re: subclassing associated classes elegantly
Darren, Your problem reminds me of the "Expression Problem", which is something that IIRC Luke's Theory idea was trying to solve. Here is the link to a paper Luke referred me to on the subject: http://scala.epfl.ch/docu/files/IC_TECH_REPORT_200433.pdf Also, you can Google the phrase "Expression Problem" and find quite a bit on the subject. Stevan On Oct 19, 2005, at 6:11 PM, Darren Duncan wrote: I'm in a long-standing situation with my module development where I want to design a set of associated classes such that invocations of submethods or class methods, such as new(), of one class by another class continue to work as expected when any or all of those classes is subclassed. I have a solution already that works, but I'm looking for the most optimal solution. An example of when this situation can arise is if person X implements a simplified XML DOM implementation using 2 classes, Document and Node, that work together, where one of those classes (Document) can create objects of the other (Node), and person Y wants to subclass the XML DOM implementation, meaning that those same Node objects made by one of person Y's Document subclass should be objects of person Y's Node subclass. To illustrate, say we had these 4 classes (the syntax may be wrong): # This is one associated class set: class A { submethod one () { return 'hello'; } submethod two () { B.four(); } } class B { submethod three () { A.one(); } submethod four () { return 'here'; } } # This is separate and optional associated class set: class C is A { submethod one () { return 'world'; } } class D is B { submethod four () { return 'there'; } } What I want to be able to do is set things up so that user code can do something that is effectively like this: my $first = A.two(); # returns 'here' my $second = B.three(); # returns 'hello' my $first = C.two(); # returns 'there' my $second = D.three(); # returns 'world' The situation is that classes C and D represent any arbitrary named 2 classes that are subclassed from A and B, and so the latter can't know the names of the former, and the latter have to work independently of C and D also. This is one variant of a solution I have come up with: # This is one associated class set: role AB { submethod name_of_class_A () { return 'A'; } submethod name_of_class_B () { return 'B'; } } class A does AB { submethod one () { return 'hello'; } submethod two () { .name_of_class_B().four(); } } class B does AB { submethod three () { .name_of_class_A().one(); } submethod four () { return 'here'; } } # This is separate and optional associated class set: role CD { submethod name_of_class_A () { return 'C'; } submethod name_of_class_B () { return 'D'; } } class C is A does CD { submethod one () { return 'world'; } } class D is B does CD { submethod four () { return 'there'; } } This is another variant of a solution I have come up with: # This is one associated class set: role AB { submethod invoke_one () { return A.one(); } submethod invoke_four () { return B.four(); } } class A does AB { submethod one () { return 'hello'; } submethod two () { .invoke_four(); } } class B does AB { submethod three () { .invoke_one(); } submethod four () { return 'here'; } } # This is separate and optional associated class set: role CD { submethod invoke_one () { return C.one(); } submethod invoke_four () { return D.four(); } } class C is A does CD { submethod one () { return 'world'; } } class D is B does CD { submethod four () { return 'there'; } } In either case, the expectation here is that the submethods of role CD will override those of role BC regardless of which class' other methods invoke those, when the invocant class is C or D. So I'm wondering what is the best way to develop my associated class sets such that it is easiest for third parties to be able to subclass-extend them. Should I use one of the two solutions above (both of which have been tried in real life, in Perl 5, the second more recently)? Or is there another solution that is better than both? Also, in such a situation as the above, is it reasonable to support easy subclassing, or would it be better to avoid that complexity and instead expect users to create objects that wrap the others instead of subclassing them? Assume also that it may be counter-productive for one class to expect user code to invoke the second class on its behalf, such as if when pair of classes is hidden behind a second pair of classes th
Re: subclassing associated classes elegantly
On Wed, Oct 19, 2005 at 03:11:21PM -0700, Darren Duncan wrote: : What are some best practices here that can be used by anyone faced by : a similar problem? My battery's running low, so I just skimmed your article, but my impression is that this is something that would be handled by virtualizing all class names within methods to be the version of the class seen by the actual object rather than the declared class. This is a behavior that has already been mandated, not just for inner classes, but any external class referenced by name. (This applies only within methods. Within a class outside the methods, names are not virtual.) Larry
subclassing associated classes elegantly
I'm in a long-standing situation with my module development where I want to design a set of associated classes such that invocations of submethods or class methods, such as new(), of one class by another class continue to work as expected when any or all of those classes is subclassed. I have a solution already that works, but I'm looking for the most optimal solution. An example of when this situation can arise is if person X implements a simplified XML DOM implementation using 2 classes, Document and Node, that work together, where one of those classes (Document) can create objects of the other (Node), and person Y wants to subclass the XML DOM implementation, meaning that those same Node objects made by one of person Y's Document subclass should be objects of person Y's Node subclass. To illustrate, say we had these 4 classes (the syntax may be wrong): # This is one associated class set: class A { submethod one () { return 'hello'; } submethod two () { B.four(); } } class B { submethod three () { A.one(); } submethod four () { return 'here'; } } # This is separate and optional associated class set: class C is A { submethod one () { return 'world'; } } class D is B { submethod four () { return 'there'; } } What I want to be able to do is set things up so that user code can do something that is effectively like this: my $first = A.two(); # returns 'here' my $second = B.three(); # returns 'hello' my $first = C.two(); # returns 'there' my $second = D.three(); # returns 'world' The situation is that classes C and D represent any arbitrary named 2 classes that are subclassed from A and B, and so the latter can't know the names of the former, and the latter have to work independently of C and D also. This is one variant of a solution I have come up with: # This is one associated class set: role AB { submethod name_of_class_A () { return 'A'; } submethod name_of_class_B () { return 'B'; } } class A does AB { submethod one () { return 'hello'; } submethod two () { .name_of_class_B().four(); } } class B does AB { submethod three () { .name_of_class_A().one(); } submethod four () { return 'here'; } } # This is separate and optional associated class set: role CD { submethod name_of_class_A () { return 'C'; } submethod name_of_class_B () { return 'D'; } } class C is A does CD { submethod one () { return 'world'; } } class D is B does CD { submethod four () { return 'there'; } } This is another variant of a solution I have come up with: # This is one associated class set: role AB { submethod invoke_one () { return A.one(); } submethod invoke_four () { return B.four(); } } class A does AB { submethod one () { return 'hello'; } submethod two () { .invoke_four(); } } class B does AB { submethod three () { .invoke_one(); } submethod four () { return 'here'; } } # This is separate and optional associated class set: role CD { submethod invoke_one () { return C.one(); } submethod invoke_four () { return D.four(); } } class C is A does CD { submethod one () { return 'world'; } } class D is B does CD { submethod four () { return 'there'; } } In either case, the expectation here is that the submethods of role CD will override those of role BC regardless of which class' other methods invoke those, when the invocant class is C or D. So I'm wondering what is the best way to develop my associated class sets such that it is easiest for third parties to be able to subclass-extend them. Should I use one of the two solutions above (both of which have been tried in real life, in Perl 5, the second more recently)? Or is there another solution that is better than both? Also, in such a situation as the above, is it reasonable to support easy subclassing, or would it be better to avoid that complexity and instead expect users to create objects that wrap the others instead of subclassing them? Assume also that it may be counter-productive for one class to expect user code to invoke the second class on its behalf, such as if when pair of classes is hidden behind a second pair of classes that mediate access to them. What are some best practices here that can be used by anyone faced by a similar problem? -- Darren Duncan