warnings dilemma

K

kj

I've read the PODs (warnings, perllexwarn) but I still don't know
how to solve this problem. Here's a toy version of it.

First some random module:

# Foo.pm
package Foo;
use strict;
use warnings;

# calling foo() will result in an 'uninitialized' warning
sub foo { my %h; exists $h{ $_[ 0 ] } }
1;

__END__



The function Foo::foo represents one of those situtations in which
the author of the module, for whatever reason, has not taken steps
to avoid a default warning.

Next, my script

use strict;
use Foo;
{ no warnings; Foo::foo(); }
exit;


Now, despite the "no warnings" in the script, when I run it I still
get the "Use of initialized value in exists" warning.

I know that I can silence the warnings by setting $SIG{__WARN__}
in the script to a suitable handler, but this leads to parsing the
text of warning messages, which is an invitation for bugs, and
basically throws the nice warnings pragma warnings hierarchy out
the window. (If there's a way to define $SIG{__WARN__} to mimic
the effects of "no warnings 'foobar'" without having to parse
warning messages in order to *guess* whether a particular warning
belongs to the "foobar" category, please let me know.)

Of course, I could remove "use warnings" from Foo.pm (or pester
its author to do so), then the warnings would *never* show up even
if the script were changed to

use strict;
use Foo;
{ use warnings; Foo::foo(); }
exit;

This is not good. Why? Because module authors are fallible like
everyone else, and despite their best efforts, a situation warranting
a warning will slip through, so it is nice to make those warnings
visible. I.e. putting "use warnings" at the top of each module
file seems to me like a fine idea. Except that then the script
*can't* turn off warnings!

I am at a loss. It seems that either alternative (including "use
warnings" in Foo.pm or leaving it out) leads to an undesirable
behavior.

IMO, the calling executable should have the final say on which
warnings get emitted. Is there a way to do this without having to
resort to defining $SIG{__WARN__} and parsing warning messages?

Thanks!

kj
 
B

Brian McCauley

I've read the PODs (warnings, perllexwarn) but I still don't know
how to solve this problem. Here's a toy version of it.

First some random module:

# Foo.pm
package Foo;
use strict;
use warnings;

# calling foo() will result in an 'uninitialized' warning
sub foo { my %h; exists $h{ $_[ 0 ] } }
1;

__END__

The function Foo::foo represents one of those situtations in which
the author of the module, for whatever reason, has not taken steps
to avoid a default warning.

So you don't like something about the way the module works. Why is
this any different from anything else about the way the module works?
Next, my script

use strict;
use Foo;
{ no warnings; Foo::foo(); }
exit;

Now, despite the "no warnings" in the script, when I run it I still
get the "Use of initialized value in exists" warning.

That's right. That's the whole point of lexical scope. You can choose
one warning level in your script and the author of the module can
choose another without the two interacting.
I know that I can silence the warnings by setting $SIG{__WARN__}
in the script to a suitable handler, but this leads to parsing the
text of warning messages, which is an invitation for bugs, and
basically throws the nice warnings pragma warnings hierarchy out
the window.

But if you objective is to break down the nice isolation that is
provided by lexically scoped warning control and want to fiddle with
warnings from another lexical scope then that's what you're stuck with
(AFAIK).
(If there's a way to define $SIG{__WARN__} to mimic
the effects of "no warnings 'foobar'" without having to parse
warning messages in order to *guess* whether a particular warning
belongs to the "foobar" category, please let me know.)

No the messages that passed to the $SIG{__WARN__} are just plain
strings they don't AFAIK have hidden information about the warning's
position in the hierarchy.

Anyhow I don't get it - I thought you wanted to filter out warning
that came from the module Foo, not warnings of a particular category.
Of course, I could remove "use warnings" from Foo.pm (or pester
its author to do so), then the warnings would *never* show up even
if the script were changed to

use strict;
use Foo;
{ use warnings; Foo::foo(); }
exit;

This is not good. Why? Because module authors are fallible like
everyone else, and despite their best efforts, a situation warranting
a warning will slip through, so it is nice to make those warnings
visible. I.e. putting "use warnings" at the top of each module
file seems to me like a fine idea. Except that then the script
*can't* turn off warnings!

Bugs in the module show up in the module. They are fixed by fixing the
module. Why is this a problem?
I am at a loss. It seems that either alternative (including "use
warnings" in Foo.pm or leaving it out) leads to an undesirable
behavior.

You could, of course, edit the module do the right thing.

sub foo { my %h; no warnings 'uninitialized'; exists $h{ $_[ 0 ] } }

This gets rid of the warning and serves as a comment that the author
is intentionally treating undef as '' in the remainder of the block.
IMO, the calling executable should have the final say on which
warnings get emitted.

That's why $SIG{__WARN__} is still useful.
Is there a way to do this without having to
resort to defining $SIG{__WARN__} and parsing warning messages?

Well the alternative is to redirect STDERR.

{
local *STDERR;
open STDERR, '>', '/dev/null'; # IIRC /dev/null is special-cased
Foo::foo();
}

Note this won't stop warnings that are sent directly to FD2 by
subprocesses or non-Perl libraries. To intercept those see (my
contributions to) numerous previous threads on the subject of
capturing STDERR.
 
K

kj

In said:
I've read the PODs (warnings, perllexwarn) but I still don't know
how to solve this problem. Here's a toy version of it.

First some random module:

# Foo.pm
package Foo;
use strict;
use warnings;

# calling foo() will result in an 'uninitialized' warning
sub foo { my %h; exists $h{ $_[ 0 ] } }
1;

__END__

The function Foo::foo represents one of those situtations in which
the author of the module, for whatever reason, has not taken steps
to avoid a default warning.
So you don't like something about the way the module works.

No, that's *not* the problem. The problem is that, as far as I
can tell, there is no good way (either through code or through
coding practices) to provide control over warnings to the calling
script. Every alternative is deficient in one way or another.
That's right. That's the whole point of lexical scope.

I disagree. I think a far more useful implementation of lexical
control is to give each lexical scope the ability to control which
warnings it allows to "bubble up" through it, in a way entirely
analogous to the lexical control of fatal errors with eval. E.g.
under this version, code like this:

if ( $verbose ) {
use warnings;
Foo::foo();
}
else {
no warnings;
Foo::foo();
}

would result in warnings only if $verbose is true. This is more
useful than what we have now, because it privileges scopes in
proportion to their proximity to the top-level scope, as it should
be. I don't understand why it wasn't designed like this in the
first place...

kj
 
B

Brian McCauley

I've read the PODs (warnings, perllexwarn) but I still don't know
how to solve this problem. Here's a toy version of it.
First some random module:
# Foo.pm
package Foo;
use strict;
use warnings;
# calling foo() will result in an 'uninitialized' warning
sub foo { my %h; exists $h{ $_[ 0 ] } }
1;
__END__
The function Foo::foo represents one of those situtations in which
the author of the module, for whatever reason, has not taken steps
to avoid a default warning.
So you don't like something about the way the module works.

No, that's *not* the problem. The problem is that, as far as I
can tell, there is no good way (either through code or through
coding practices) to provide control over warnings to the calling
script. Every alternative is deficient in one way or another.

Well, yes that's true. Nothing's perfect.
I disagree. I think a far more useful implementation of lexical
control is to give each lexical scope the ability to control which
warnings it allows to "bubble up" through it, in a way entirely
analogous to the lexical control of fatal errors with eval.

The scope of control of fatal errors with eval() is _not_ lexical.
"Lexically scoped" describes the way "use warnings" or "use strict"
works now. What you want is the opposite of lexical scope - "dynamic
scope". This is what we had before we had lexical control with
local($^W) and what we still have with local($SIG{__WARN__}).
E.g.
under this version, code like this:

if ( $verbose ) {
use warnings;
Foo::foo();
}
else {
no warnings;
Foo::foo();
}

would result in warnings only if $verbose is true. This is more
useful than what we have now,

No it isn't. I'm not saying that the functionality you want would not
be useful sometimes but it would be usefull less often than what we
have now. I want to be able to suppress or promote warnings
selectively in _my_ code without an action-at-a-distance on other code
I happen to be calling.
because it privileges scopes in
proportion to their proximity to the top-level scope, as it should
be.

I disagree. The descision as to which warning-causing circumstances
are expected and which are not (and which should be errors) belongs as
close as possible to where the expectation applies.
I don't understand why it wasn't designed like this in the
first place...

Because the designers agree with my way of thinking.

With perl 5.10's new caller() you could write a lexically scoped
pragma that actually had dynamically scoped effect because you have
access to all the lexical scope hints in all calling stack frames.
However the bit that's responsible for determining what warning
categories are enabled is not AFAIK replacable so you couldn't make
this selective by category. As I said before that probably doesn't
matter because for what you are trying to do filtering by category
does not make much sense anyhow.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top