--- chromatic <[EMAIL PROTECTED]> wrote:
> On Thursday, July 24, 2003, at 08:49 AM, David Wheeler wrote:
>
> > On Wednesday, July 23, 2003, at 05:57 PM, chromatic wrote:
> >
> >> The first is a deeper question -- besides inheritance, there's
> >> delegation, aggregation, and reimplementation (think mock objects)
>
> >> that can make two classes have equivalent interfaces. I'd like
> some
> >> way to mark this equivalence *without* having to inherit from an
> >> abstract base class and I wish that interface equivalence were
> >> checked before inheritance, as per Luke's idea.
> >
> > Sounds like you want Java-style "interfaces" to me.
>
> No, I think Java interfaces are a kluge to get around copying a
> broken type system and the lack of multiple inheritance.
Multiple Inheritance != Protocols | Interfaces
How much C++ code have you seen with "unused" stuff in the objects
because "I had to inherit from that class to get the MI behavior I
wanted, but I no longer use those attributes."
Protocols/Interfaces is a way of saying "My structure is none of your
damn business, but I comply with the rules you've set."
MI, on the other hand, can be implemented with a protocol and a has-a
relationship, albeit at a significant cost in coding dispatch methods.
There's an argument for supporting both.
class Foo is all(DessertTopping, FloorWax) {
}
> I don't want to litter both the caller and the callee with interface
> declarations that do nothing but say "this thing here understands the
> same methods as that thing there". The caller, fine -- that's the
> place it belongs.
I disagree, and I hope you've simply swapped terms around.
I think you want to declare "I comply with ruleset X" at the callee
object level. That enables the compiler to (1) check that you're not
lying; and (2) optimize based on (1).
> If I have to modify the callee to do this, I've insufficient
> polymorphism.
At the "caller" side, you want to say "I require something which
complies with ruleset X" and have it be enforced to a user-configurable
extent.
Obviously calling a method which doesn't exist should be an error. But
(especially in large systems) it should be possible to slack off on the
call-side checking, because you know you're doing the checking on the
callee side at compile time.
> Think of it this way. If you write Perl 5 code like this:
>
> sub some_method
> {
> my $self = shift;
> die "Bad object" unless ref $self = 'Some::Class';
> # do something useful...
> }
>
> someone will have to change or override some_method() if he wants to
> subclass it. You could make his life a little easier by writing:
>
> sub some_method
> {
> my $self = shift;
> die "Bad object" unless $self->isa( 'Some::Class' );
> # do something useful...
> }
>
> I'm suggesting to go the next step and let the code say, "Hey, if it
> acts like an instance of Some::Class, I don't care where it gets its
> behavior. I'll treat it like an instance of Some::Class." That's
> what
> I do with Class::ActsLike, and that's what I'd like to see here:
>
> sub some_method
> {
> my $self = shift;
> die "Bad object" unless $self->acts_like( 'Some::Class' );
> # do something useful...
> }
>
I notice all this is on the callee side. I'm hoping you swapped er/ee
above.
> Now it doesn't care whether I've inherited, aggregated, delegated, or
> reimplemented. My argument is that it shouldn't have to care. It
> should only care that I've somehow promised that what I'm passing in
> behaves like it expects it to behave. How it does that is
> uninteresting.
I agree. Luke agrees. The extent to which this is formalized is open
for discussion, but I think Damian doesn't agree (see his example some
time back about class Dog vs. class Tree).
=Austin