http://www.perlmonks.org?node_id=85556

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

Last January I posted a question on how to force Perl to check at compile time that the subroutines I call exist.

The extremely wise Tye advised to "sort your subroutines in reverse topological order (so subroutines are declared before you use them), then call all your subroutines using barewords."

Recently I was using CGI.pm, and I made the mistake of properly spelling the word "referrer()" instead spelling it "referer()" as CGI.pm demands. The script compiled fine and gave only run-time errors telling me that referrer() does not exist.

Since I did not write CGI.pm I cannot sort it in topological order. How can I force Perl to check that the functions I call in the CPAN modules exist?

  • Comment on Forcing Compile Time Checking That Subs Exist

Replies are listed 'Best First'.
Re: Forcing Compile Time Checking That Subs Exist
by japhy (Canon) on Jun 04, 2001 at 23:09 UTC
    Call the function without parens. When you use the module, the functions get defined at compile-time.

    japhy -- Perl and Regex Hacker
      Removing the parentheses when calling "referrer()" instead of the properly (for CGI.pm) spelled referer() seems to have no effect. Perl only catches the error at runtime.

        japhy's suggestion only works if you are importing the functions from CGI and not using the OO interface.

                - tye (but my friends call me "Tye")
Re: Forcing Compile Time Checking That Subs Exist
by bikeNomad (Priest) on Jun 04, 2001 at 23:41 UTC
    Welcome to dynamic languages!

    You can't get compile-time checking of method calls (I'm assuming you're using good OO style). After all, you can define and undefine subroutines at runtime, and there's no easy way to do static analysis to find out what class an object is when you do the call.

    However, one (partial) solution is to make sure that your test cases (you do have test cases for all your code, right?) have full coverage. Run your tests with -d:Coverage or my Quick Perl coverage analyzer and make sure that every method call is being invoked. The reason that this is "partial" is that you could have objects that are a different class at some later time, but this is relatively uncommon.

      Much as I love Perl and hate to admit it, it strikes me as a serious deficiency that Perl will not warn me at compile-time if, using an OO interface to a module such as CGI.pm, I accidentally mistype a function name.

      Larry's slogan is "There's More Than One Way To Do It" but when it comes to compile-time checking of an OO module's function calls it would be more accurate to say "There's No Way To Do It."

      A hairline crack is developing in my solid wall of faith in Perl. I keep thinking that there must be a way to do compile-time checking of an OO module's function calls. Otherwise people will spend hours as I did trying to find their own typing errors.

        Maybe the compiler's not the right tool to catch these errors.

        It's a hard nut to crack because of things like AUTOLOAD, Autosplit, and run-time access to class symbol tables. We won't even get into the abomination that is multiple dispatch, because I'm still wrapping it around my brain.

        I catch a lot more errors running unit tests on my code than I do running it through the compiler and looking for warnings. If you exercise your code paths sufficiently as bikeNomad suggests, you'd get closer to what you want than the compiler can provide.

        It's not exactly what you want, but it's working pretty well for me.

        Keep the faith, Brother!

        Having been a Smalltalk user for at least 5 years now, one thing that helps in typical Smalltalk environments is their checking of method names when you define new methods. Every time you edit a method, it's recompiled; the compiler does a simple check to see if any of the method names you're using haven't been defined yet. If so, you get a warning. This has helped me detect a lot of typos in my code.

        I'm thinking that a similar strategy could be used with Perl, by scanning programs like this:

        • For each 'use'd or 'require'd package, make a defined symbol list (easiest way to do this is probably just to use B::Xref).
        • Scan your program for method calls (or, more simply, for words, removing all the Perl pre-defined words).
        • Make a list of all the method calls (or words) in your program that don't match any of the subroutines defined in your included packages

        This is a simple strategy, and it should be easy to implement. Tell me if it works!

        I still prefer full testing, though. Have you read anything about Extreme Programming techniques? One of the XP tenets is to write tests FIRST.