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

Reply via email to