diotalevi has asked for the wisdom of the Perl Monks concerning the following question:

I've been adding some code to perl's B modules to get it to respect OO subclassing but I'm finding that I have to occasionally query that something isn't just a subclass.

Given the following structure BINOP is UNOP is OP, I'd always find that BINOP isa OP. Occasionally I need to know that I really do have an OP object or something that would like to pretend it is an OP object.

I assume this is a sign that subclassing was the wrong route for BINOP and UNOP. Or is it? Is there a circumstance under OO where this is expected?

What's a good perl query for this? Since I know all the things that have subclassed OP I could ask for $obj->isa('OP') and not any { $obj->isa($_) } qw( BINOP UNOP ). That's ugly to look at and expensive to ask for. It'd be much easier to just use ref($obj) but that'd be wrong because then I couldn't use a Test::MockObject object which earnestly wanted to pretend to be a OP object.

ref($obj) can't normally be lied to so now I think I want to have a $obj->is('OP') method which could ignore ISA. I just invented the name ->is(CLASS). Does this method exist under a normal name somewhere in OO-speak? I want to at least steal the common name for the inheritance-ignoring-isa query.

[I suppose should mention that I really meant to write B::OP, B::UNOP, and B::BINOP but found all the B:: parts distracting so I removed them.]

Replies are listed 'Best First'.
Re: ISA but no farther?
by ikegami (Patriarch) on Jul 20, 2006 at 17:57 UTC

    Test for the property you are searching, not the class.

    package OP; sub has_my_property { return 1; } package BINOP; sub has_my_property { return 0; } package UNOP; sub has_my_property { return 0; }

    etc. The Test::MockObject object can claim to have the property if it so desires.

    I can't help you further without knowing why you need to know if it's exactly an OP or not.

Re: ISA but no farther?
by Tanktalus (Canon) on Jul 20, 2006 at 16:29 UTC

    I realise that I'm missing the precise context of why you want to find out you have a real OP object rather than something derived from OP (directly or indirectly), but part of the purpose of deriving from some base class is to pretend to be an object of that type, while changing the behaviour. So I'm trying to think why you (normally) would want to check that something is an OP, but only an OP.

    I put "normally" there just because I realise you're probably doing some deep dark magicks (based solely on the fact you're inside B), and thus probably have a good reason to do this. But since Test::MockObject probably fakes things by changing its own ISA to go through inheritance, you're probably looking for a fairly significant overhaul of some of the object infrastructure of perl to allow T::MO to fake something without anyone else faking it.

    That said, it makes perfect sense to me that a binary operator ISA operator. Because it is. However, a binary operator IS NOT a unary operator. They may share some code in common, but they aren't really the same thing. It's sorta like some of the OO examples that have Rectangle as a subclass of Square - which is wrong, because a Square ISA Rectangle, but a Rectangle is not (always) a Square. From an implementation perspective, you end up with smaller objects for Square if you put them in the object hierarchy backwards, which may be why you have BINOP as a subclass of UNOP.

      Please don't mind the relationship between the types of things and their names. That reflects the underlying C structs and how OO is emulated in C.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re: ISA but no farther?
by diotalevi (Canon) on Jul 20, 2006 at 16:22 UTC

    In chatter Corion suggested replacing 'XXX' eq ref( $obj ) with defined( blessed( $obj ) ) and $obj->ref( 'XXX' ) having first done *UNIVERSAL::ref = sub { ref($_[0]) eq $_[1] } which would allow everything that doesn't redefine ->ref(...) to continue to function while giving space for a user function to lie with its own ->ref(...) function.

Re: ISA but no farther?
by ysth (Canon) on Jul 20, 2006 at 16:29 UTC
    Why not ref($obj) eq "OP"? But usually needing to know if something is just an OP, not a subclass thereof, does indicate a poor class structure. Why do you need to know?

      If I give you a Test::MockObject that can do everything an OP object can but isn't actually blessed into the OP class, you'll think you don't have an OP object if you use ref($obj) eq 'OP. The point is that I want to rule out things that say they are subclasses of OP but not things that would like to think that they are really, truely, an OP object.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        Sorry, missed that part; then you need to fix Test::MockObject to allow something like
        ref($obj) eq 'OP' || ref($obj) eq 'Test::MockObject' && $obj->mocks('O +P')