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

I've noticed several people (for example here) calling can method in this way: UNIVERSAL::can('Test', 'foo'). Doesn't this break inheritance? Imagine class Test be a subclass of SuperTest which implements method foo(). Will this code return true or false?

I tried a test, and UNIVERSAL::can is aware of inheritance. And I'm little bit confused now. UNIVERSAL::can('Test', 'foo') looks like a bad practice when compared to Test->can('foo'). Is it just a hack in UNIVERSAL::can that make it work in the 'bad' way or is it a planned feature? Is UNIVERSAL::can('Test', 'foo') used for performance reasons (to avoid traversing ISA hierarchy twice)?

Replies are listed 'Best First'.
Re: Calling can method
by jeroenes (Priest) on May 30, 2001 at 13:03 UTC
    You just have no choice, if you don't have an instance of the class. So if there is no object created, the UNIVERSAL::can is the only way to test if that class provides that method.

    Cheers,

    Jeroen
    "We are not alone"(FZ)

    Update: Ahum... indeed. The perl OO is really confusing. But, now I remember again, UNIVERSAL::can('Test','foo') is actually the same as Test->can('foo'). Because in the last case, the word Test gets unshifted into @_, and the method 'can' is found in UNIVERSAL. So internally, actually UNIVERSAL::can is called, with the args ('Test', @_), which comes down to the same.

    So this is actually a feature, not a bug {grin}

    To clarify a bit more (mehopes):

    package Test; package main; print "it works\n" if Test->UNIVERSAL::can('can'); print "it works\n" if Test->SUPER::can('can');
    You see? The Package::can only gives the route to the method (if not given, perl finds it from ISA). The -> only tells which thing to unshift in @_.

    Of course, the sub need a way to filter out whether they are called with a Package or an object. So the trick doesn't work with all methods.

    It's explained also in the 'Inheritance' section of perltoot.

      No no no no,

      I can call any static method by ClassName->method. Including 'can' method. I can safely call Test->can('foo'). I have tried that. It works and I use it frequently.

        You can't safely call $x->can('foo') though, although you can always call UNIVERSAL::can($x, 'foo'), which is where the idiom comes from. True, it's overkill for the class case, but for the instance case, it's mandatory.

        -- Randal L. Schwartz, Perl hacker