I prefer to write good error messages and then depend on
them. You prefer to use the debugger.
...over writing good error messages? No. And I never said
that. That is quite a big jump you've made ): I just said
that I prefer using a debugger over adding temporary trace.
But I did figure out some of our disagreement. I'm really
only talking about Carp::croak(), which I feel was meant
for what I call "precondition failures". In many other
languages, the simple preconditions for a function are that
you specify the right number of arguments and that they
each have the correct type. These are checked at compile
time.
Perl doesn't offer such compile-time preconditions most of
the time (rarely you can reasonably use prototypes for this)
so a Perl programmer who includes lots of error checks is
going to generate fatal errors when a function gets the
wrong number of arguments, for example.
This type of error is extremely likely to just be a simple
coding error in the immediate caller of the function (more
on this later). So it makes sense to have Carp::croak()
report the error as having come from the immediate caller
and including a stack back trace is not likely needed.
From the documentation, this seems to be what Carp::croak()
does and what it was intended for. But it appears that
the documentation is wrong and Carp::croak() looks at
inheritance to decide how far up the call stack to go.
Now, I can see some use for generating warnings
that seem to come from the user code and can see using
inheritance to figure that out (imperfect but not too
unreasonably so)1. But a fatal error is a
different matter.
For the module to try to kill the script, there must be a
serious problem. These usually amount to precondition
failures or assertion failures. Simple precondition
failures can be pinned on the immediate caller (modulo
wrappers to be discussed shortly) because the source of
the error is almost always right there. Complex
preconditions should include a stack trace (which can
skip the current function context if you like). Assertion
failures should also include a stack trace. That is because
we may suspect that the user code is at fault but we
shouldn't delete useful information about the state of
the module even though we don't think that this
is the source of the problem. If we know that the
user code is at fault, then we should be returning a
failure indication (or throwing an exception), but not
trying to kill the script.
I have this tiny suspicion that Carp::croak() used to
work this way but then had patches applied that didn't
include documentation changes. But that is just a tiny
hunch.
Now, Perl doesn't have a preprocessor so you often end
up with simple wrappers in your module (that don't check
their arguments before passing them on) so the simple
preconditions might be due to code more than one level
up the call stack. Since a module should be tested before
it is released, there shouldn't be any precondition failures
that are due to code in the same module. So it makes sense
to bubble up within the module.
Now, for some huge packages of modules like LWP or CGI,
there are lots of modules developed together. Well, CGI
never croak()s. LWP croaks a whole 6 times. Either force
it to specify that each or all of its calls to
Carp::croak() should skip more than one package or have
Carp.pm use inheritance along with the fact that
all of the package names fall under the same hierarchy.
The few big packages of modules shouldn't be setting the
behavior for Carp.pm when it is easy (like it is) to find
cases that this behavior breaks for.
I didn't look at LWP long enough to see whether any of the croak()s could have originated from user code and passed through a different module/package of LWP (thus requiring
an @ISA scan to find the user code and the proper place to
report the error). But I did notice that several of the
error messages would be pretty confusing if this did
happen.
In some ways, I don't think what Carp.pm is doing is horribly wrong. But it is starting to sound to me like you are "fixing" Carp.pm without a design document and that is part of our problem.
So Exporter complaining about %EXPORT_TAGS being set
up incorrectly should be throwing a precondition failure
which shouldn't (by default) look at (just) inheritance.
"Fixing" the problem by lying about your inheritance
during a window of time is what sounds like "playing games"
to me.
What you keep calling "playing cute games" is simply
initializing variables close to when you declare them
and before you might use them. This is often easy in
Perl. But for "static" variables, doing so currently
often requires the very simple step of putting the
initialization into a BEGIN block. Nothing fancy nor
tricky nor in the slightest way "cute". (:
And in this case in particular you will guaranteed get
wrong behaviour from both old and current versions of Perl
Nope. Never have and probably never will. I'd only get
wrong behavior if I'd also made stupid mistakes about
setting up %EXPORT_TAGS or such. And then I'd have to do
that where I have multiple packages inheriting from each
other. Yep, I pretty much guarentee that I won't ever
run into that. Even if I did, I'd find those during module
testing where the error being reported in the wrong place
is pretty minor.
Not initializing statics at compile time has bitten me
several times, for different reasons each time. The only
specific cause that I recall is circular module dependancy
which isn't something you run into often but then that
only accounts for one of my bites.
I've seen this advocated by several people, so I'm sure
they've been bitten by it too. I'm not telling you to
trust their decision about whether or not to do this, I'm
telling you that several people have been bitten by it
enough that they decided to change. You have one case
of the reverse that I know I don't care about. I have one
specific case that I suspect you don't care about. But
there are quite a few cases out there on my side.
Plus, your case really seems to me to be a case of two
wrongs making a right. Carp.pm gets the inheritance
tree wrong which prevents its other bug from firing.
I consider it evidence that you should initialize
statics in BEGIN blocks, because look at all that can
happen during that window!
Well you know my opinion about the stupid misuses
of $Carp::CarpLevel in the past. First of all when
proper coding depends on programmers always getting
things right, that is guaranteed to go wrong often.
Um, so if programmers have to get things right then
sometimes they won't and then things will go wrong.
Is that a tautology? Yeah, $Carp::CarpLevel was a terrible
design choice. But having a per-module equivalent of
$Carp::CarpLevel as well as a perl-call equivalent would
be useful and fairly easy to do. And if it designed
well and documented, then programmers will very often
get it right. Somehow you think that you setting
the one true behavior, that you will get it
right more often than programmers will? Only if the
programmers are given a horrid, undocumented way to do
it. Don't let how bad $Carp::CarpLevel was prevent you
from designing and implementing a good solution.
Now, you can certainly choose to let this one obscure bug prevent you from coding defensively when it comes to uninitialized static variables; but I think that would be a mistake. :)
1 I'm not a big fan of warnings from modules.
Warnings from a module can be quite useful to the script
writer (aka module user) but are usually delivered to the
script user (non-programmer). The script writer can trap
them with $SIG{__WARN__}, for example, but that will also
catch warnings that are meant for the script user. So if
I want to send a programmer warning from a module, I'll
provide a delivery mechanism other than warn.
-
tye
(but my friends call me "Tye")