develooper Front page | perl.perl5.porters | Postings from November 2000

Re: Plan to try again with Carp

Thread Previous | Thread Next
Ben Tilly
November 27, 2000 04:59
Re: Plan to try again with Carp
Message ID:
Hugo wrote:
>In <>, "Ben Tilly" writes:
>:Hugo wrote:
>:>In <>, "Ben Tilly" writes:
>:>:Feedback?  Comments?
>:>It isn't clear to me why you want to kill $Carp::CarpLevel, though
>:>I read your email through a couple of times to try and understand
>:>this. I regularly use the moral equivalent of:
>:>   local $Carp::CarpLevel = $Carp::CarpLevel + 1;
>:>.. in diagnostic functions.
>:Well there are two places that it exists.  I think that
>:both are bad.  First of all for short messages it
>:results in simply confusing behaviour:
>I agree it is confusing - I'd never used it that way, so never
>encountered the confusion. I don't understand why it doesn't do
>exactly the same as longmess: print the diagnostic as if it had
>been invoked by caller($CarpLevel).

Is this really desirable either?

Consider the case of Exporter().  Someone chooses to set
$Carp::CarpLevel to edit Exporter out of long debugging
messages.  But now "use Bar ('hello');" is called in
package Foo, that creates an error because Foo is not
willing to export any error called 'hello', so the
heuristic that Carp uses starts from package Bar, and
immediately skips back to reporting it from within
package Baz which had a "use Foo;" in it.

So now the error is reported from Baz for no apparent

If Foo happened to be the main body of the program, though,
then it gets better.  You get croak() turned into a
confess() with the actual location of the error
obfuscated for your pleasure!

This is the exact example that led me to take a closer
look at what Exporter and Carp did...

No, mixing and matching whatever heuristic is used for
short messages with lots of explicit control in ways
that don't naturally fit that heuristic either will
lead to duplicated logic as people try to tie out their
explicit control to the heuristic, or will lead to
confusing behaviour when things don't work as expected
by someone who is familiar with the heuristic.  Neither
is good in my books.

>:The other place it shows up is in long messages.  There
>:it actually does do something moderately useful.  It
>:edits call levels out.  If (as a debugger might) you
>:have kept track of call levels, then you can use it to
>:edit yourself out of the messages.  Now suppose that
>:you want to guarantee that Exporter is supposed to
>:not show up if someone sets $Carp::Verbose to a true
>:value.  Now you have to go through how much work to
>:figure out the correct $Carp::CarpLevel to set?
>   local $Carp::CarpLevel = $Carp::CarpLevel + 1;
>in each function you want to edit out. There, that was easy. :)

So because of a stupid mechanism you need to take a
constant runtime performance penalty?  Plus this will
not - I guarantee you - get maintained.  Programmers
tend to not worry about error conditions until after
they are hit.  Maintaining this takes constant vigilance
and failure to maintain this kind of structure does not
lead to any errors.  And it leads to the temptation to
say, "Well I know that in this situation I am always 3
call levels away." and then hardcode it.

No, establishing decent error reporting has to be made
as close to a no-brainer as possible or it will not
happen in the real world.

>:Since that is apparently the point of having it, I would
>:prefer to set up a simpler API to get that effect.
>The effect I want is exactly the longmess effect: edit out a
>single caller() level. I may well do that within the same package
>that the error should really be reported from, so it is not
>sufficient for the purpose to be able to specify only packages
>to be edited out.

Why do you want this effect?

For 90% of the usage is this the most natural interface?

Why not put functions you want edited out into their own

>:If people think that I am being too extreme, then
>:please tell me what behaviour you think it should
>:have and we can implement that.  But I will be
>:shocked and amazed if people can some up with good
>:a priori reasons why the current behaviour makes
>:sense or is maintainable.  Certainly the places where
>:I have seen people try to use it have usually led to
>I've never had a use for the shortmess() behaviour, but that may
>just be me. Maybe we need a %IgnorePackage as you suggest, but
>I hope we won't lose the existing $CarpLevel effect for longmess(),
>and I'd quite like to see such an effect available for shortmess(),
>preferably using the same mechanism.

When I implement, I can provide a somewhat reasonable
$CarpLevel effect, but I won't like it.

>As a sidenote, I have had problems in the past using packages that
>carped their errors up a level even though they were generating the
>error themselves. This can make debugging real difficult. However,
>when this is done by means of a localised $CarpLevel change it is
>easy to override it remotely with a
>   local $Carp::CarpLevel = $Carp::CarpLevel - 1;
>.. and I suspect %IgnorePackage would not permit so easy a remedy.

Gee, so with $Carp::CarpLevel if everyone uses it exactly
like you want them to (something which I am willing to
bet won't happen) then you can tweak things.

With my mechanism the easiest way for people to play such
games is:

package Foo;
$Carp::Internal{Foo} = 1;
# etc

which means that the key command happens during
initialization and so you are free to later issue:

delete $Carp::Internal{Foo};

or even

local %Carp::Internal;

Both, of course, depend on the module author doing
The Right Thing, but with $Carp::CarpLevel that
thing takes more thought and care and demonstrably
is not happening, while with my proposed mechanism
I believe it would be the obvious way to do things.
(How often do you find people playing games within
functions with @EXPORT, @ISA, etc, etc?)

Get more from the Web.  FREE MSN Explorer download :

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About