--- 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



Reply via email to