On 8/8/06, Yuval Kogman <[EMAIL PROTECTED]> wrote:
The way it could work is a bit like this:
class Mail::TheOneTrueWay {
does Mail::SomeAPI is weak {
method header; # this method has different semantics for
# each role. It would normally conflict.
}
does Mail::SomeOtherAPI is weak {
method header;
}
method body; # this method is shared between the two roles
}
This code raises a few questions:
Mail::TheOneTrueWay.new.header; # which one?
A related question: if Mail::SomeAPI and Mail::SomeOtherAPI both
exported a method, say "send", and you mentioned it outside the weak
role blocks, which one does it call.
Presumably the answer to both of these questions is "error". But that
answer has disastrous consequences, for now that even though the class
it does both of these roles, if you don't use type annotation, it in
fact does neither of them.
Delegates are another way around this but let's face it:
1. they're not as popular as they should be
2. they're more classes to write
3. they're harder to use
Well, yeah, but I think they're the right solution.
In a situation where I have the same name meaning multiple things, I
want to keep them as separate as possible, because DWIMs will just get
me in trouble (because the code looks perfect, so it's hard to track
down if it doesn't behave perfectly).
Delegates make your intention explicit and independent of type
annotations (which is a plus in my book). Have your class do neither
role, so that you get an error when you didn't say what you meant.
However, that still leaves the problem of code that is in the roles
and used in the classes. In the case that there is duplicate
functionality, I would say pick the one you like better and do that
one, and write an adapter for the other one.
In the case that there is functionality you want from both, I'm at a
loss. If I were forced to use standard OO tools, I'd probably do
something awful like this:
class SomeAPIPart {
does Mail::SomeAPI;
has $!body;
method header() {
# do stuff $!body.header to make it conform
}
}
# same for SomeOtherAPIPart
class TheOneTrueWay {
has $!some_api = SomeAPIPart.new(body => self);
has $!some_other_api = SomeOtherAPIPart.new(body => self);
# use stuff from $!some_api and $!some_other_api
}
Where SomeAPIPart and SomeOtherAPIPart serve as two-way adapters to
those interfaces.
That is a horrible amount of structure accomplishing relatively
little. However, I think in practical situations a lot of that
structure would be mechanical, so one could write a module to handle
it.
I agree with the problem you are addressing; there's no good way in
module-free Perl to solve it. However, having thought a great deal
about objects with "views" when I was constructing theory.pod, I just
don't think they're a good idea---ever. An automated adapter class
solution is our best bet.
Oh, and hello everyone. Long time no see :-)
Luke