
btilly at gmail
Oct 21, 2006, 11:19 PM
Views: 468
Permalink
|
|
Why aren't %Carp::Internal and %Carp::CarpInternal documented?
|
|
Glancing at the source code for a current copy of Carp, I see that Jos I. Boumans <kane[at]dwim.org> claimed that %Carp::CarpInternal and %Carp::Internal do not work as advertised and therefore removed the documentation. That is false. I just double-checked, and they do what I said they did. Really. What putting a package in %Carp::Internal does is keeps Carp from deciding that an error should be reported as being from a call from that package to somewhere else. What putting a package in %Carp::CarpInternal does is keeps Carp from deciding that an error should be reported as being from a call to that package. If anyone wants to test it, all of the major cases are tested in the program at the end of this email. In this program there are 4 calls of interest. We have main line 1 calls, calls Foo line 1, calls Bar line 1, calls Baz line 1 which carps. I try all 16 combinations of having Bar and Baz in or not in %Carp::Internal and %Carp::CarpInternal. If you run it, you will find the following: - The message is reported at Bar line 1 unless the call from Bar to Baz is marked safe by having Baz in %Carp::CarpInternal or Bar in %Carp::Internal. - If Baz is in %Carp::CarpInternal or Bar is in %Carp::Internal, the message is reported at Foo line 1 or main line 1 depending on whether the call from Foo to Bar is marked safe by Bar being in %Carp::CarpInternal. In short if A calls B, that call can be marked safe by having A be in %Carp::Internal or by having B be in %Carp::CarpInternal. Exactly as was once advertised. Furthermore looking at the documentation for Carp, I see that there is now documentation of global variables. %Carp::Internal and %Carp::CarpInternal are not documented. But $Carp::CarpLevel is. However $Carp::CarpLevel is far more problematic than the other two. As an illustration I point you to http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2006-10/msg00324.html where David Nicol demonstrates how one should NOT implement a certain piece of functionality. His implementation will cause any croak or carp to either report errors as being from a package very high in the call stack that has nothing to do with the error, or will turn carp/croak into cluck/confess. The reason being that the accounting of calls that he's doing assumes that he has to bump $Carp::CarpLevel up one for every call level. Which is right for cluck/confess, but is very, very wrong for carp/croak. (You actually want to bump it one for each package that it wouldn't decide to skip on its own. Deciding whether it would skip a package requires doing what Carp does in Carp::Heavy's short_error_loc.) Incidentally the right way to do what David Nicol was trying to do in his code is: $Carp::Internal{ __PACKAGE__ } = 1; And then just use the regular functions from Carp. Regards, Ben PS Here is the test program #! /usr/bin/perl -w use strict; *STDERR = *STDOUT; for my $bar_internal (0, 1) { $Carp::Internal{Bar} = $bar_internal; for my $bar_carpinternal (0, 1) { $Carp::CarpInternal{Bar} = $bar_carpinternal; for my $baz_internal (0, 1) { $Carp::Internal{Baz} = $baz_internal; for my $baz_carpinternal (0, 1) { $Carp::CarpInternal{Baz} = $baz_carpinternal; print "Bar " . ($bar_internal ? "is" : "isn't") . " in %Internal\n"; print "Bar " . ($bar_carpinternal ? "is" : "isn't") . " in %CarpInternal\n"; print "Baz " . ($baz_internal ? "is" : "isn't") . " in %Internal\n"; print "Baz " . ($baz_carpinternal ? "is" : "isn't") . " in %CarpInternal\n"; # line 1 "main" Foo::foo(); print STDERR "\n"; } } } } package Foo; sub foo { # line 1 "Foo" Bar::bar(); } package Bar; sub bar { # line 1 "Bar" Baz::baz(); } package Baz; use Carp qw(cluck); sub baz { # line 1 "Baz" cluck("Baz::baz was called"); }
|