Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Re^3: Class::Interface -- isa() Considered Harmful

by adrianh (Chancellor)
on Jan 19, 2003 at 20:50 UTC ( [id://228230]=note: print w/replies, xml ) Need Help??


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

To me, there's a world of difference between saying "even though this mock object inherits absolutely no data or behavior from this class hierarchy, it's a member of this class hierarchy" and "this mock object has the same fingerprint as objects of this class and can be used in their place".

To me there isn't. I think that's the basis for my confusion. To me the inheritance hierarchy is the exact way you express the relationship between different objects with the same "fingerprint" (which am reading as contract).

I don't understand what advantage inventing a different kind of hierarchy gives you.

A mock object is not a DBI object. It's not a CGI object.

Why not? Seriously :-)

Most of my mocks are implemented as full classes and use the @ISA hierarchy to identify themselves.

I'd like to avoid forcing composition, delegation, and equivalence relationships into the inheritance scheme. If my substitutable object does not fit within the class hierarchy conceptually, why should I have to lie to the compiler and all future maintenance programmers and say that it does?

I don't see how composition or delegation would come into the inheritance scheme. They're not ISA inheritance relationships. If somebody says a car-driver isa car or a library isa book they're just plain wrong.

On the other hand equivalence is, to me, what ISA relationships are all about.

Can you give an example that shows where ISA wouldn't be appropriate?

Replies are listed 'Best First'.
Re: Re: Re: Re: Class::Interface -- isa() Considered Harmful
by chromatic (Archbishop) on Jan 19, 2003 at 21:37 UTC

    Inheritance does two completely different things in Perl.

    First, it expresses a conceptual relationship. This is the hierarchy you mention. If you need to model buildings, a library is a more specific type of building. So is a restaurant.

    Second, it provides a place to look for methods called on the object that aren't defined in the class itself. This is inheritance of behavior.

    There are plenty of other ways to make sure all of the methods are in place. You can define them all yourself. You can set up an AUTOLOAD scheme, as Test::MockObject does. You can use mixins. You can delegate to another object (with a proxy or a bridge). You can contain another object (with composition).

    I can take care of #2 by any of those other methods. That's what my mocks do. Why should I have to rely on inheritance to provide #1?

    I'd rather have a more general solution, one that allows me to say "an object of this type behaves as an object of this other type". If that's in place, inheritance can still work just fine -- derived objects are automatically marked as being able to act as objects of their parent classes.

    That's exactly what Class::Interface does.

    Can you give an example that shows where ISA wouldn't be appropriate?

    A Car object contains for Wheel objects. I have code that wants to find the circumference of all Wheels in my universe, calling get_circumference() to do so. It looks at all of the objects in my universe to see if they can handle the operations a Wheel can handle. Since Car does not inherit from Wheel, it can't check isa(). If Car is marked as having the same fingerprint as Wheel, it will work.

    I'm not interested in any solution that suggests "You should have an abstract base class for hasWheel or delegatesToWheel." I just want to be able to say "Car can handle messages to Wheel" without expressing a relationship that's not there or exposing how the Car handles Wheel messages.

      It seems to be as bad an example as the Airport/Arcade one. The Car doesn't handle Wheel messages. It has four wheels that handle Wheel messages. I don't say let_air_our to the Car, I send that to a specific wheel.

      Makeshifts last the longest.

      A Car object contains for Wheel objects. I have code that wants to find the circumference of all Wheels in my universe, calling get_circumference() to do so. ... If Car is marked as having the same fingerprint as Wheel, it will work.

      But a car has four wheels? Surely $wheel->get_circumference and $car->get_circumference can't be doing the same thing so they don't have the same "fingerprint"?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://228230]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (3)
As of 2024-03-28 15:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found