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

Is there a B::Lint plug-in or another module that can be used to provide warnings for undefined object methods? We have been using OO perl a fair bit lately, and the Lint module is becoming less useful for catching this class of bug in our applications. I've done some digging but nothing is jumping out at me as a common solution to this issue.

Replies are listed 'Best First'.
Re: linting for undefined object methods
by ikegami (Patriarch) on Sep 01, 2009 at 20:52 UTC

    Do you mean making sure method exists given the code $x->method()?

    How do you expect the linter to know all of the classes of which $x could be an instance and all of the namespaces whose name $x could contain.

    I guess you could do an imperfect job if you knew some possible values for $x. That raises the following question:

    How do you expect the linter to know any of the classes of which $x could be an instance or any of the namespaces whose name $x could contain.

    Update: Now takes class methods into consideration.

      We are using a simple, restrictive OO methodology which should be fairly well lintable at compile time. All methods are known at compile time. We are not using perl's AUTOLOAD feature or any other sort of dynamic method generation. All objects are created with a call to CLASS->new() (no dynamic re-blessing) and the class hierarchy is contained in @ISA. I guess this is too much of a corner case for support in the general B::Lint module, but the bottom line is we miss catchable stuff at compile time that causes real problems. Maybe I should write a plugin for Lint for this sort of situation.

        By having the linter make the giant assumption that all subs are methods, that tells you a bit about $self, but not enough. It only helps determine that cases such as the following aren't problems:

        { package Base; sub x { ... } } { package Child; our @ISA = 'Base'; sub y { shift->x } }

        However, it doesn't help determine that something is a problem. For example, is there a problem in the following?

        package Package; sub y { shift->x }

        No, turns out package Package is just a role:

        { package SomeRole; # Implementor must provide y sub y { shift->x } } { package Class; our @ISA = 'SomeRole'; sub x { ... } }

        But that's not the real test. How often do you call a child method that doesn't exist? I expect the majority of problems to be in code such as the following:

        sub some_method { my ($self, $arg) = @_ ... $arg->other_method(); ... }
        or
        sub some_method { my ($self) = @_ ... $self->attribute->other_method(); ... }

        The linter knows absolutely nothing about the class or object whose method other_method is being called, so it has no idea if other_method exists for that class or object.

        Thanks for explaining the "corner cases".

        Maybe I should write a plugin for Lint for this sort of situation.

        Maybe you should consider to have a look into PPI for static parsing and/or B::Xref and something like B::Concise for parsing after compilation.

        Cheers Rolf

        UPDATET distinction between static and compilation parsing

Re: linting for undefined object methods
by LanX (Saint) on Sep 01, 2009 at 20:27 UTC
    I'm confused, what exactly do you want? Do I miss a special restriction?

    Lint means compile-time checking, but perl methods are evaluated at run-time and there are myriads of different OOP moduls for perl abstracting the interface. Not mentioning dynamic AUTOLOAD of methods or adding methods on the fly at run-time.

    This question is strongly related to static parsing and why refactoring and intellisense are so complicated to realize in perl.

    You see there is no simple answer if your not providing more information about your case.

    In general the answer is: "No it's not possible while allowing perl's full dynamic flexibility!"

    Cheers Rolf

    UPDATE: One approach could be to simulate static typing, see Re: Compile-time/Auto-test method checking?.