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