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) Create your Node, subclassing Node::Base 4) Load Document 5) Rename Document to Document::Base 6) Create your Document, subclassing Document::Base Something along the lines of: package Node::Mine; use Node; *Node::Base = *Node; delete $main::{Node}; package Node; use base 'Node::Base'; etc. So, I figure that with packages being a lot simpler to work with in P6, that should be a lot easier to handle. Especially given that packages and modules are now first-class. Rob