Oh Carp!

Recently got hit with this error:

Goto undefined subroutine &Carp::shortmess_real at /usr/share/perl/5.10/Carp.pm line 41.

What's going on?

Older versions of Carp (like the one included with Debian Squeeze, 1.11) puts the actual implementation in Carp::Heavy. Carp::Heavy is loaded on demand when one of Carp's routines like carp() or cluck() is called.

Newer versions of Carp (at least since 1.22, when it first appears independently on CPAN) no longer does this. For some reason the author decides to move everything into Carp, making Carp::Heavy empty.

The problem arises when an older version of Carp tries to call a newer version of Carp::Heavy, hoping to find an implementation that is no longer there. And this can quite easily happen because Carp::Heavy's loading is delayed (which I reckon is the original intent, to reduce startup overhead as much as possible).

Our application ships its own CPAN modules and has this piece of code on its scripts:

use FindBin;
use lib "$FindBin::Bin/../lib"; # use our version of CPAN modules

FindBin uses Carp, and at this point, system-wide modules are used. However, after the "use lib" statement, application-shipped path is searched first. When something carp()'s or cluck()'s, the new version of Carp::Heavy from our application's lib/ is loaded. Boom!

Moral of the story: delayed loading has its cons.

Possible stop-gap solution: add "use Carp::Heavy" before "use lib" line, to force loading old version of Carp::Heavy.

Possible long term solutions:

1) Our application ships older version of Carp.

2) Carp::Heavy should detect older version of Carp and do something about it (preferably making everything seamlessly working).

3) Carp::Heavy should just be deleted from the new distribution. What's the point of having it around if it's empty anyway? It hurts older Carp and provides no gain to newer Carp.

I'm torn between #2 and #3, but lean slightly towards #2. By doing #3, some users who preload Carp::Heavy explicitly will be hit. Even though users should not preload Carp::Heavy explicitly in the first place, the whole mess has been created, and backward-compatibility should be maintained.

6 Comments

This problem seemed familiar, so I checked back and sure enough it came up on PerlMonks a few months ago.

Another solution would be for Carp.pm itself to do:

# Suppress Carp::Heavy being loaded
$INC{'Carp/Heavy.pm'} = __FILE__;
 
# Use aliases to provide all the old functions
*Carp::Heavy::foo = \&foo;
*Carp::Heavy::bar = \&bar;

That way, as long as a new version of Carp was loaded fairly early on (and perl -MCarp could be used to achieve that) everything would work out fine.

What about this:

4) Delete Carp from your application

Hi

I'd vote for Toby's suggestion /and/ (3).

Pre-loaders of Carp::Heavy would have to change their code, sure, but I think they should have to, since it cleans up their code.

Leave a comment

About Steven Haryanto

user-pic A programmer (mostly Perl 5 nowadays). My CPAN ID: SHARYANTO. I'm sedusedan on perlmonks. My twitter is stevenharyanto (but I don't tweet much). Follow me on github: sharyanto.