in reply to Re: Re: Re: Class::Interface -- isa() Considered Harmful
in thread Class::Interface -- isa() Considered Harmful

Since both you and perrin have responded among similar lines, it seems that my examples are unclear and aren't communicating very well. Let me address your points in order and see if I can clear up my intent.

  1. It is my opinion that Java provides interfaces in lieu of multiple inheritance. I think that's a lousy special case that doesn't address the real issue. (I find myself saying that about Java quite often.)
  2. I agree very much. I think that that addresses the real issue backwards, however. My code shouldn't have to care whether it's dealing with an object that isa specific type. I'd much rather have it check to see that it can act as a specific type.
  3. I disagree that the only way to implement an interface without inheritance is to write a wrapper. I've got a generic mock object that implements any interface you can imagine without wrapping at all. What I lack is a way to say, "Does this object act as if it were an object of this type?"

My goal is twofold:

In other words, I don't want this:

package A::Class; sub some_method { my ($self, $object) = @_; die "Object is not what I expect" unless UNIVERSAL::isa( $object, 'Some::Class' ); $object->some_other_method(); $object->some_method_or_other(); }

That unnecessarily dictates that $object has to inherit from Some::Class, or at least fake up enough so that it can fool UNIVERSAL::isa(). Consider a test case:

use Test::More 'no_plan'; use Test::MockObject; my $mock = Test::MockObject->new(); use_ok( 'A::Class' ); my $a = A::Class->new(); isa_ok( $a, 'A::Class' ); $mock->set_true( 'some_other_method' ) ->set_true( 'some_method_or_other' ); $a->some_method( $mock );

That dies, unnecessarily, because Test::MockObject does not subclass Some::Class. That's not what I want to express, either.

What I really want to express is that $object, whatever it is, ought to act like a Some::Class object. If it inherits from Some::Class, that's fine. If it delegates to a Some::Class object, that's fine. If it contains a Some::Class object, that's fine. If it simply conforms to the Some::Class interface, that's fine.

I don't think "reworking the object model" to make the other three possibilities fit into the inheritance scheme is the right approach. I think the interface approach is more general and, if implemented correctly, can handle all four possibilities easily.

I do think my examples were unclear though, and apologize for the confusion they caused.

Replies are listed 'Best First'.
Re: Re: Re: Re: Re: Class::Interface -- isa() Considered Harmful
by djantzen (Priest) on Jan 16, 2003 at 21:17 UTC

    Okay, the problem then is that we've got different definitions of what an interface is. For me, coming from C++ and Java, the technical definition of an interface is an abstract superclass that provides only static data members, abstract method declarations, and that indicates an is-a relationship. To quote from Java in a Nutshell: "When you define an interface, you are creating a new reference type, just as you are when you define a class." (p. 112).

    What you're talking about is behavior without association to a reference type. You essentially want a list of things that an object can do with its type information stripped away. In this sense, bart's suggestion to use can seems very close to what you want, as dws's astute observation that different classes may "mean" different things by similarly named methods is only relevant insofar as you're concerned with is-a relationships and getting one particular class-specific behavior. If your Test::MockObject is the prototypical application for this idea then I think using can is fine, as the objective there is, inasmuch as I can gather from a quick perusal, to isolate the code you're testing from other dependencies. This is a great idea, and it's much better than the one-off approach I've sometimes had to use in temporarily redefining methods just to report back some placeholder information. Nonetheless, I must cling to the belief for the time being at least that "real" code going into production or publication would suffer greatly in terms of maintainability from this sort of thing. And in that sense fixing the object model is almost always going to be preferrable to warping inheritance chains.

    Due to the substantial precedence for associating interfaces with reference types, I think a different term would be helpful here. It sounds like what you want is shorthand for grouping a set of methods together into a set, but one not unified by type. Maybe "possible behaviors" would suffice?