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
that mediate access to them.
What are some best practices here that can be used by anyone faced
by a similar problem?
-- Darren Duncan