Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Perl: porters

Why aren't %Carp::Internal and %Carp::CarpInternal documented?

 

 

Perl porters RSS feed   Index | Next | Previous | View Threaded


btilly at gmail

Oct 21, 2006, 11:19 PM

Post #1 of 7 (457 views)
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");
}


btilly at gmail

Oct 22, 2006, 2:07 PM

Post #2 of 7 (432 views)
Permalink
Re: Why aren't %Carp::Internal and %Carp::CarpInternal documented? [In reply to]

On 10/22/06, Jos Boumans <kane[at]dwim.org> wrote:
> > 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.
>
> I did not remove documentation -- I've added documentation for the other
> global variables, as none of them were documented. The comment reads:
>
> # Comments added by Jos I. Boumans <kane[at]dwim.org> 11-Aug-2004
> # I can not get %CarpInternal or %Internal to work as advertised,
> # therefor leaving it out of the below documentation.
> # $CarpLevel may be decprecated according to the last comment, but
> # after 6 years, it's still around and in heavy use ;)

Hrm, right. With that reminder I remember having been unhappy enough
with how the previous internal interfaces were written that I didn't
want to publically document the new internal interfaces. But if we're
going to document internal interfaces, I think we should document the
reliable ones.

Yes, $CarpLevel may be around and in heavy use, but those uses
generally don't really do what people think they do. In fact the
documented example that was put in the Carp documentation doesn't do
what the documentation claims it does! (A double irony, the original
carp() function does what the documentation claims they want to do
with that example.)

> > 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...
>
> I'm glad you managed to illustrate and test the behaviour as advertised.
> Perhaps
> you could convert this illustration to a patch to the documentation and
> test suite of Carp?

See the end of this message. I patched the documentation and the test
suite to correct a number of things. Specifically I did the
following:

- Documented %Carp::Internal and %Carp::CarpInternal.

- Rewrote the documentation of $Carp::CarpLevel. In so doing I
removed the example that didn't do what it said it did, explained what
it actually does do, and explained how people usually messed it up. I
also pointed people at the alternatives that are available and are
more likely to do the right thing.

- Removed documentation of shortmess and longmess. Unfortunately
longmess doesn't do anything particularly reasonable, and it can't be
made to do so because of backwards compatibility with code that
depended on the old behaviour.

- Added an internal comment in the implementation of longmess
explaining why it doesn't do what you'd think it should do.

- Added tests to verify various documented aspects of Carp's
behaviour, including the newly documented %Carp::Internal and
%Carp::CarpInternal.

- Removed a couple of comments from Carp/Heavy.pm.

- Modified the implementation in Carp/Heavy.pm so that it was easier
to document. The change is that carp/croak will not report on any
line within a package in %Carp::CarpInternal. This makes no practical
difference because they previously did not report on any calls TO a
line within a package in %Carp::CarpInternal, and the functions within
Carp only call package Carp. But it is easier to precisely document
this behaviour than the old.

Cheers,
Ben

--- Carp.pm.bak 2006-10-22 09:59:26.000000000 -0700
+++ Carp.pm 2006-10-22 11:28:55.000000000 -0700
@@ -60,10 +60,6 @@

confess - die of errors with stack backtrace

-shortmess - return the message that carp and croak produce
-
-longmess - return the message that cluck and confess produce
-
=head1 SYNOPSIS

use Carp;
@@ -72,30 +68,27 @@
use Carp qw(cluck);
cluck "This is how we got here!";

- print FH Carp::shortmess("This will have caller's details added");
- print FH Carp::longmess("This will have stack backtrace added");
-
=head1 DESCRIPTION

The Carp routines are useful in your own modules because
they act like die() or warn(), but with a message which is more
likely to be useful to a user of your module. In the case of
cluck, confess, and longmess that context is a summary of every
-call in the call-stack. For a shorter message you can use carp,
-croak or shortmess which report the error as being from where
-your module was called. There is no guarantee that that is where
-the error was, but it is a good educated guess.
+call in the call-stack. For a shorter message you can use C<carp>
+or C<croak> which report the error as being from where your module
+was called. There is no guarantee that that is where the error
+was, but it is a good educated guess.

You can also alter the way the output and logic of C<Carp> works, by
changing some global variables in the C<Carp> namespace. See the
section on C<GLOBAL VARIABLES> below.

-Here is a more complete description of how shortmess works. What
-it does is search the call-stack for a function call stack where
-it hasn't been told that there shouldn't be an error. If every
-call is marked safe, it then gives up and gives a full stack
-backtrace instead. In other words it presumes that the first likely
-looking potential suspect is guilty. Its rules for telling whether
+Here is a more complete description of how c<carp> and c<croak> work.
+What they do is search the call-stack for a function call stack where
+they have not been told that there shouldn't be an error. If every
+call is marked safe, they give up and give a full stack backtrace
+instead. In other words they presume that the first likely looking
+potential suspect is guilty. Their rules for telling whether
a call shouldn't generate errors work as follows:

=over 4
@@ -107,15 +100,15 @@
=item 2.

Packages claim that there won't be errors on calls to or from
-packages explicitly marked as safe by inclusion in @CARP_NOT, or
-(if that array is empty) @ISA. The ability to override what
+packages explicitly marked as safe by inclusion in C<@CARP_NOT>, or
+(if that array is empty) C<@ISA>. The ability to override what
@ISA says is new in 5.8.

=item 3.

The trust in item 2 is transitive. If A trusts B, and B
-trusts C, then A trusts C. So if you do not override @ISA
-with @CARP_NOT, then this trust relationship is identical to,
+trusts C, then A trusts C. So if you do not override C<@ISA>
+with C<@CARP_NOT>, then this trust relationship is identical to,
"inherits from".

=item 4.
@@ -126,8 +119,15 @@

=item 5.

-Any call to Carp is safe. (This rule is what keeps it from
-reporting the error where you call carp/croak/shortmess.)
+Any call to Perl's warning system (eg Carp itself) is safe.
+(This rule is what keeps it from reporting the error at the
+point where you call C<carp> or C<croak>.)
+
+=item 6.
+
+C<$Carp::CarpLevel> can be set to skip a fixed number of additional
+call levels. Using this is not recommended because it is very
+difficult to get it to behave correctly.

=back

@@ -151,21 +151,6 @@

=head1 GLOBAL VARIABLES

-=head2 $Carp::CarpLevel
-
-This variable determines how many call frames are to be skipped when
-reporting where an error occurred on a call to one of C<Carp>'s
-functions. For example:
-
- $Carp::CarpLevel = 1;
- sub bar { .... or _error('Wrong input') }
- sub _error { Carp::carp(@_) }
-
-This would make Carp report the error as coming from C<bar>'s caller,
-rather than from C<_error>'s caller, as it normally would.
-
-Defaults to C<0>.
-
=head2 $Carp::MaxEvalLen

This variable determines how many characters of a string-eval are to
@@ -190,11 +175,57 @@

=head2 $Carp::Verbose

-This variable makes C<Carp> use the C<longmess> function at all times.
-This effectively means that all calls to C<carp> become C<cluck> and
-all calls to C<croak> become C<confess>.
+This variable makes C<carp> and C<cluck> generate stack backtraces
+just like C<cluck> and C<confess>. This is how C<use Carp 'verbose'>
+is implemented internally.
+
+Defaults to C<0>.
+
+=head2 %Carp::Internal
+
+This says what packages are internal to Perl. C<Carp> will never
+report an error as being from a line in a package that is internal to
+Perl. For example:
+
+ $Carp::Internal{ __PACKAGE__ };
+ # time passes...
+ sub foo { ... or confess("whatever") };
+
+would give a full stack backtrace starting from the first caller
+outside of __PACKAGE__. (Unless that package was also internal to
+Perl.)
+
+=head2 %Carp::CarpInternal
+
+This says which packages are internal to Perl's warning system. For
+generating a full stack backtrace this is the same as being internal
+to Perl, the stack backtrace will not start inside packages that are
+listed in C<%Carp::CarpInternal>. But it is slightly different for
+the summary message generated by C<carp> or C<croak>. There errors
+will not be reported on any lines that are calling packages in
+C<%Carp::CarpInternal>.
+
+For example C<Carp> itself is listed in C<%Carp::CarpInternal>.
+Therefore the full stack backtrace from C<confess> will not start
+inside of C<Carp>, and the short message from calling C<croak> is
+not placed on the line where C<croak> was called.
+
+=head2 $Carp::CarpLevel
+
+This variable determines how many additional call frames are to be
+skipped that would not otherwise be when reporting where an error
+occurred on a call to one of C<Carp>'s functions. It is fairly easy
+to count these call frames on calls that generate a full stack
+backtrace. However it is much harder to do this accounting for calls
+that generate a short message. Usually people skip too many call
+frames. If they are lucky they skip enough that C<Carp> goes all of
+the way through the call stack, realizes that something is wrong, and
+then generates a full stack backtrace. If they are unlucky then the
+error is reported from somewhere misleading very high in the call
+stack.

-Note, this is analogous to using C<use Carp 'verbose'>.
+Therefore it is best to avoid C<$Carp::CarpLevel>. Instead use
+C<@CARP_NOT>, C<%Carp::Internal> and %Carp::CarpInternal>.

Defaults to C<0>.

--- Heavy.pm.bak 2006-10-22 10:07:04.000000000 -0700
+++ Heavy.pm 2006-10-22 14:06:36.000000000 -0700
@@ -15,10 +15,6 @@
# these are called, they require Carp::Heavy which installs the real
# routines.

-# Comments added by Andy Wardley <abw[at]kfs.org> 09-Apr-98, based on an
-# _almost_ complete understanding of the package. Corrections and
-# comments are welcome.
-
# The members of %Internal are packages that are internal to perl.
# Carp will not report errors from within these packages if it
# can. The members of %CarpInternal are internal to Perl's warning
@@ -28,12 +24,6 @@
# $Max(EvalLen|(Arg(Len|Nums)) variables are used to specify how the eval
# text and function arguments should be formatted when printed.

-# Comments added by Jos I. Boumans <kane[at]dwim.org> 11-Aug-2004
-# I can not get %CarpInternal or %Internal to work as advertised,
-# therefore leaving it out of the below documentation.
-# $CarpLevel may be decprecated according to the last comment, but
-# after 6 years, it's still around and in heavy use ;)
-
# disable these by default, so they can live w/o require Carp
$CarpInternal{Carp}++;
$CarpInternal{warnings}++;
@@ -48,6 +38,11 @@

sub longmess_real {
# Icky backwards compatibility wrapper. :-(
+ #
+ # The story is that the original implementation hard-coded the
+ # number of call levels to go back, so calls to longmess were off
+ # by one. Other code began calling longmess and expecting this
+ # behaviour, so the replacement has to emulate that behaviour.
my $call_pack = caller();
if ($Internal{$call_pack} or $CarpInternal{$call_pack}) {
return longmess_heavy(@_);
@@ -234,6 +229,7 @@

return 0 unless defined($caller); # What happened?
redo if $Internal{$caller};
+ redo if $CarpInternal{$caller};
redo if $CarpInternal{$called};
redo if trusts($called, $caller, $cache);
redo if trusts($caller, $called, $cache);

--- Carp.t.bak 2006-10-22 11:00:53.000000000 -0700
+++ Carp.t 2006-10-22 13:35:55.000000000 -0700
@@ -8,7 +8,7 @@

use Carp qw(carp cluck croak confess);

-plan tests => 21;
+plan tests => 36;

ok 1;

@@ -72,6 +72,87 @@
};
ok !$warning, q/'...::CARP_NOT used only once' warning from Carp::Heavy/;

+# Test the location of error messages.
+like(A::short(), qr/^Error at C/, "Short messages skip carped package");
+
+{
+ local @C::ISA = "D";
+ like(A::short(), qr/^Error at B/, "Short messages skip inheritance");
+}
+
+{
+ local @D::ISA = "C";
+ like(A::short(), qr/^Error at B/, "Short messages skip inheritance");
+}
+
+{
+ local @D::ISA = "B";
+ local @B::ISA = "C";
+ like(A::short(), qr/^Error at A/, "Inheritance is transitive");
+}
+
+{
+ local @B::ISA = "D";
+ local @C::ISA = "B";
+ like(A::short(), qr/^Error at A/, "Inheritance is transitive");
+}
+
+{
+ local @C::CARP_NOT = "D";
+ like(A::short(), qr/^Error at B/, "Short messages see \@CARP_NOT");
+}
+
+{
+ local @D::CARP_NOT = "C";
+ like(A::short(), qr/^Error at B/, "Short messages see \@CARP_NOT");
+}
+
+{
+ local @D::CARP_NOT = "B";
+ local @B::CARP_NOT = "C";
+ like(A::short(), qr/^Error at A/, "\@CARP_NOT is transitive");
+}
+
+{
+ local @B::CARP_NOT = "D";
+ local @C::CARP_NOT = "B";
+ like(A::short(), qr/^Error at A/, "\@CARP_NOT is transitive");
+}
+
+{
+ local @D::ISA = "C";
+ local @D::CARP_NOT = "B";
+ like(A::short(), qr/^Error at C/, "\@CARP_NOT overrides inheritance");
+}
+
+{
+ local @D::ISA = "B";
+ local @D::CARP_NOT = "C";
+ like(A::short(), qr/^Error at B/, "\@CARP_NOT overrides inheritance");
+}
+
+# %Carp::Internal
+{
+ local $Carp::Internal{C} = 1;
+ like(A::short(), qr/^Error at B/, "Short doesn't report Internal");
+}
+
+{
+ local $Carp::Internal{D} = 1;
+ like(A::long(), qr/^Error at C/, "Long doesn't report Internal");
+}
+
+# %Carp::CarpInternal
+{
+ local $Carp::CarpInternal{D} = 1;
+ like(A::short(), qr/^Error at B/
+ , "Short doesn't report calls to CarpInternal");
+}
+
+{
+ local $Carp::CarpInternal{D} = 1;
+ like(A::long(), qr/^Error at C/, "Long doesn't report CarpInternal");
+}

# tests for global variables
sub x { carp @_ }
@@ -158,7 +239,6 @@
}
}

-
{
local $TODO = "VMS exit status semantics don't work this way" if $Is_VMS;

@@ -173,3 +253,45 @@

is($?>>8, 42, 'confess() doesn\'t clobber $!');
}
+
+# line 1 "A"
+package A;
+sub short {
+ B::short();
+}
+
+sub long {
+ B::long();
+}
+
+# line 1 "B"
+package B;
+sub short {
+ C::short();
+}
+
+sub long {
+ C::long();
+}
+
+# line 1 "C"
+package C;
+sub short {
+ D::short();
+}
+
+sub long {
+ D::long();
+}
+
+# line 1 "D"
+package D;
+sub short {
+ eval{ Carp::croak("Error") };
+ return $@;
+}
+
+sub long {
+ eval{ Carp::confess("Error") };
+ return $@;
+}


davidnicol at gmail

Oct 22, 2006, 9:17 PM

Post #3 of 7 (440 views)
Permalink
Re: Why aren't %Carp::Internal and %Carp::CarpInternal documented? [In reply to]

On 10/22/06, Ben Tilly <btilly[at]gmail.com> wrote:
> 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

Groovy! Some days I am proud to be loud and ignorant.

To get back to the original poster's issue, the only thing that
Carp::Clan appears to do that can't be done by manipulating existing
Carp hooks is that it has a really easy use-time invocation that
automatically does the equivalent of adding packages to Carp::Internal.

Perhaps an unimport method could be added to Carp.

...
no Carp; # adds __PACKAGE__ to Carp::Internal
...

This could be done by slipping the following somewhere
into Carp.pm, perhaps after rewriting the title of the pod
section:



sub unimport{
shift;
if(@_){
$Internal{$_} = 1 for @_;
}else{
$Internal{caller()} = 1;
}
};

=head1 Suppressing Reports From Friend Package Frames

To cause Carp to skip a package it would not otherwise skip,
include

no Carp;

within the package, which is a shorthand way to set
C<$Carp::Internal{ __PACKAGE__ }> to a true value.

no Carp qw/Alice Bob Chuck/;

causes Carp to skip frames from the Alice, Bob and Chuck packages
instead of the current package.

no Carp __PACKAGE__, qw/Alice Bob Chuck/;

causes Carp to skip frames from those as well as the current.

=cut


twists at gmail

Oct 23, 2006, 9:17 AM

Post #4 of 7 (436 views)
Permalink
Re: Why aren't %Carp::Internal and %Carp::CarpInternal documented? [In reply to]

On 10/22/06, David Nicol <davidnicol[at]gmail.com> wrote:
> On 10/22/06, Ben Tilly <btilly[at]gmail.com> wrote:
> > 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
>
> Groovy! Some days I am proud to be loud and ignorant.
>
> To get back to the original poster's issue, the only thing that
> Carp::Clan appears to do that can't be done by manipulating existing
> Carp hooks is that it has a really easy use-time invocation that
> automatically does the equivalent of adding packages to Carp::Internal.

To get the Carp::Clan benefits, you'd have Carp.pm generate custom
carp functions for each place that requests one.

That is, instead of getting the single \&Carp::carp (or wherever it
lives under Carp::), your package gets a custom function which sets
$Carp::Internal before redispatching to the one-true-Carp.

Or heck, Carp::Clan loses 99% of it's code and just becomes a wrapper.
I'd *so* love that. I took over maintenance for it when I found it
didn't handle overloaded objects correctly but I've been kind of
dreading merging it back to Ben's Carp.

It's a happy day when I can throw away that much code. If someone else
wants to go publish Carp::Clan distributions, they're welcome to do
that fix as well. I'll give you the PAUSE perms to the namespace. If
you wait, I'll get to this eventualy but I'm moving to Seattle and
doing other things first.

Josh


btilly at gmail

Oct 23, 2006, 10:30 AM

Post #5 of 7 (432 views)
Permalink
Re: Why aren't %Carp::Internal and %Carp::CarpInternal documented? [In reply to]

On 10/22/06, David Nicol <davidnicol[at]gmail.com> wrote:
> On 10/22/06, Ben Tilly <btilly[at]gmail.com> wrote:
> > 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
>
> Groovy! Some days I am proud to be loud and ignorant.

Well, it looks like your ignorance consisted of believing Carp's
documentation. :-)

> To get back to the original poster's issue, the only thing that
> Carp::Clan appears to do that can't be done by manipulating existing
> Carp hooks is that it has a really easy use-time invocation that
> automatically does the equivalent of adding packages to Carp::Internal.
>
> Perhaps an unimport method could be added to Carp.
>
> ...
> no Carp; # adds __PACKAGE__ to Carp::Internal
> ...
>
> This could be done by slipping the following somewhere
> into Carp.pm, perhaps after rewriting the title of the pod
> section:

YMMV, but I would find this interface very unintuitive. I think of
"no Foo" as a way to turn a pragma off. I don't think of it as a way
to leave something on and modify its behaviour.

> sub unimport{
> shift;
> if(@_){
> $Internal{$_} = 1 for @_;
> }else{
> $Internal{caller()} = 1;
> }
> };
>
> =head1 Suppressing Reports From Friend Package Frames
>
> To cause Carp to skip a package it would not otherwise skip,
> include
>
> no Carp;
>
> within the package, which is a shorthand way to set
> C<$Carp::Internal{ __PACKAGE__ }> to a true value.
>
> no Carp qw/Alice Bob Chuck/;
>
> causes Carp to skip frames from the Alice, Bob and Chuck packages
> instead of the current package.
>
> no Carp __PACKAGE__, qw/Alice Bob Chuck/;
>
> causes Carp to skip frames from those as well as the current.
>
> =cut
>
Well it doesn't entirely skip those frames. What it does is avoids
starting on them. But if you are printing a full stack backtrace, you
get a full stack backtrace from the point where you asked for it
onwards. No calls are skipped in that backtrace.

Cheers,
Ben


btilly at gmail

Oct 23, 2006, 10:42 AM

Post #6 of 7 (432 views)
Permalink
Re: Why aren't %Carp::Internal and %Carp::CarpInternal documented? [In reply to]

On 10/23/06, Joshua ben Jore <twists[at]gmail.com> wrote:
> On 10/22/06, David Nicol <davidnicol[at]gmail.com> wrote:
> > On 10/22/06, Ben Tilly <btilly[at]gmail.com> wrote:
> > > 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
> >
> > Groovy! Some days I am proud to be loud and ignorant.
> >
> > To get back to the original poster's issue, the only thing that
> > Carp::Clan appears to do that can't be done by manipulating existing
> > Carp hooks is that it has a really easy use-time invocation that
> > automatically does the equivalent of adding packages to Carp::Internal.
>
> To get the Carp::Clan benefits, you'd have Carp.pm generate custom
> carp functions for each place that requests one.

Looking at the documentation for Carp::Clan, it looks simpler than
that. What is trying to be accomplished is similar to what I was
trying to accomplish with @CARP_NOT, namely separate inheritance from
the idea of, "This package says that calls from that package will not
cause problems." However its interface looks a little more complex
than the one I provided.

Perhaps the right solution is to allow packages to have a CARP_NOT
subroutine that takes another package and says whether that package is
safe. Carp does not currently support that, but it wouldn't be hard
to make it do so. And then Carp::Clan can be implemented by exporting
an appropriate CARP_NOT subroutine, and then re-exporting Carp's
functions.

> That is, instead of getting the single \&Carp::carp (or wherever it
> lives under Carp::), your package gets a custom function which sets
> $Carp::Internal before redispatching to the one-true-Carp.
>
> Or heck, Carp::Clan loses 99% of it's code and just becomes a wrapper.
> I'd *so* love that. I took over maintenance for it when I found it
> didn't handle overloaded objects correctly but I've been kind of
> dreading merging it back to Ben's Carp.

I think Carp needs a little more intelligence before taking that
approach. What do you think of the way that I suggested handling it?

> It's a happy day when I can throw away that much code. If someone else
> wants to go publish Carp::Clan distributions, they're welcome to do
> that fix as well. I'll give you the PAUSE perms to the namespace. If
> you wait, I'll get to this eventualy but I'm moving to Seattle and
> doing other things first.

Well I could do it pretty easily, but only if Carp could become a real
CPAN module. (So that the rewritten Carp::Clan distribution can have
an appropriate dependency.)

Cheers,
Ben


rgarciasuarez at gmail

Nov 14, 2006, 2:19 AM

Post #7 of 7 (404 views)
Permalink
Re: Why aren't %Carp::Internal and %Carp::CarpInternal documented? [In reply to]

On 22/10/06, Ben Tilly <btilly[at]gmail.com> wrote:
> See the end of this message. I patched the documentation and the test
> suite to correct a number of things. Specifically I did the
> following:
>
> - Documented %Carp::Internal and %Carp::CarpInternal.
>
> - Rewrote the documentation of $Carp::CarpLevel. In so doing I
> removed the example that didn't do what it said it did, explained what
> it actually does do, and explained how people usually messed it up. I
> also pointed people at the alternatives that are available and are
> more likely to do the right thing.
>
> - Removed documentation of shortmess and longmess. Unfortunately
> longmess doesn't do anything particularly reasonable, and it can't be
> made to do so because of backwards compatibility with code that
> depended on the old behaviour.
>
> - Added an internal comment in the implementation of longmess
> explaining why it doesn't do what you'd think it should do.
>
> - Added tests to verify various documented aspects of Carp's
> behaviour, including the newly documented %Carp::Internal and
> %Carp::CarpInternal.
>
> - Removed a couple of comments from Carp/Heavy.pm.
>
> - Modified the implementation in Carp/Heavy.pm so that it was easier
> to document. The change is that carp/croak will not report on any
> line within a package in %Carp::CarpInternal. This makes no practical
> difference because they previously did not report on any calls TO a
> line within a package in %Carp::CarpInternal, and the functions within
> Carp only call package Carp. But it is easier to precisely document
> this behaviour than the old.

Thanks, applied as #29270 to bleadperl (also bumping $VERSION).

> +This says what packages are internal to Perl. C<Carp> will never
> +report an error as being from a line in a package that is internal to
> +Perl. For example:
> +
> + $Carp::Internal{ __PACKAGE__ };

I changed this to:
$Carp::Internal{ __PACKAGE__ }++;

> + # time passes...
> + sub foo { ... or confess("whatever") };
> +
> +would give a full stack backtrace starting from the first caller
> +outside of __PACKAGE__. (Unless that package was also internal to
> +Perl.)

Perl porters RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact lists@gossamer-threads.com
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.