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