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

Who doesn't like perl -w and use warnings; and use strict; and perl -MO=Lint,-all myprog.pl? However, I just had a simple problem in OO coding style that I wish had been caught. As I am writing this, I think it may not be an OO thing as much as a module/package thing.

My problem was this: I mispelled a class. More specif., I mispelled an exception class after an eval. For example:

eval { $obj->method() }; if ($@) { if (my $exception = My::Excpetion::Thingy->caught()) { do_something(); } else { do_the_other_thing(); } }
You see, My::Exception::Thingy was being caught, but my code was executing do_the_other_thing(); because I mispelled "Exception" in my ->caught().

My big picture questions are these. I am guessing that B::Lint would have to be aware of Exception::Class class definition syntax to catch this. If I wanted Lint to help me with Object::InsideOut syntax that situtation would be the same. Has stuff of this nature already been completed? My CPAN and Google searches haven't yielded anything. Is there some other easier way that I'm missing? If there is no easy answer, does Perl 6 offer an improvement?

I guess the essential nitty-gritty thing is: when using Perl OO, am I stuck catching typos as runtime bugs?

Replies are listed 'Best First'.
Re: Perl OO Lint
by ikegami (Patriarch) on Mar 13, 2006 at 18:00 UTC
    I don't see do_the_other_thing could have been executed because of the typo. I get, as I should,
    Can't locate object method "caught" via package "My::Excpetion::Thingy +" (perhaps you forgot to load "My::Excpetion::Thingy"?) at script.pl +line 8.

    True, it's a runtime error, but that's necessary since functions can be loaded at any time (including through AUTOLOAD) and @ISA can change at any time. Perl has no way of knowing at compile-time whether My::Excpetion::Thingy->caught will be valid any or all times that statement will be executed.

    For example, I sometimes do:

    if ($@) { require Carp; Carp::croak(...); }

    Carp::croak doesn't exist until the require is executed, which is only executed at run-time when the exception occurs. A compile-time check would think this is an error. However, I'll cede that it could be useful for lint to give an (overridable) *warning*.

      Oopsie! Now I see why I wasn't getting the "Can't locate object method...via package..." error. Here is the actual code with names changed to protect the innocent (i.e. me).
      eval { $lock->create() }; if (my $exception = My::Execption::Lock::Exists->caught()) { while ($lock->query()) { sleep 180; } exit 0; } die $@ if $@;
      Because my if () was always false due to a mispelling, I was just dieing with the prior eval error message, thus supressing the "missing object method" error message. Egads!

      My shame for all Perl monks to see.

        What are you talking about? That code still gives the Can't locate object method "caught" via package "My::Execption::Lock::Exists" (perhaps you forgot to load "My::Execption::Lock::Exists"?) error message.

        The if is never false (as you say) or even true, since perl dies from the type before the if expression gets completely evaluated. Similarly, the die is never reached, since the if encountered a fatal error.

        I suspect the if was within eval's block.

Re: Perl OO Lint
by diotalevi (Canon) on Mar 13, 2006 at 23:46 UTC

    I wrote an article for Perl Hacks on exactly this subject. Extend B::Lint to check for non-existant classes/methods. There's three parts I don't remember exactly what to do here but you could easily enough find out by reading the 5.9.3+ perl's B::Lint docs or B::Lint::Pluggable for earlier versions. If you bug me in the chatterbox later, I may be able to pull up what exactly goes in the missing parts. Or just learn to do this yourself.

    package B::Lint::StrictOO; use B::Lint; use if ! B::Lint->can('register_plugin'), 'B::Lint::Pluggable'; B::Lint->register_plugin( ..., [ 'oo' ] ); # I forget what goes in the +re sub match { my ( $op, $check_href ) = @_; if ( $check_href->{oo} ) { if ( $op->name eq 'entersub' ) { my $class = $op->first->sibling->...; # something. Again, +I forget exactly my $method = $op->first->sibling->sibling->...; # Another +part I don't remember exactly # validate both $class and $method } } }

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊