warnings dilemma

Discussion in 'Perl Misc' started by kj, May 10, 2007.

  1. kj

    kj Guest

    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

    --
    NOTE: In my address everything before the first period is backwards;
    and the last period, and everything after it, should be discarded.
     
    kj, May 10, 2007
    #1
    1. Advertising

  2. On May 10, 5:28 pm, kj <> wrote:
    > 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.
     
    Brian McCauley, May 10, 2007
    #2
    1. Advertising

  3. kj

    kj Guest

    In <> Brian McCauley <> writes:

    >On May 10, 5:28 pm, kj <> wrote:
    >> 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.

    >> 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.


    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
    --
    NOTE: In my address everything before the first period is backwards;
    and the last period, and everything after it, should be discarded.
     
    kj, May 10, 2007
    #3
  4. On 10 May, 22:05, kj <> wrote:
    > In <> Brian McCauley <> writes:
    >
    >
    >
    > >On May 10, 5:28 pm, kj <> wrote:
    > >> 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.

    > >> 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.

    >
    > 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.
     
    Brian McCauley, May 11, 2007
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris
    Replies:
    0
    Views:
    410
    Chris
    Nov 10, 2003
  2. Kevin Spencer

    Events Dilemma

    Kevin Spencer, Oct 25, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    361
    Bishop
    Oct 25, 2004
  3. =?Utf-8?B?RGVtZXRyaQ==?=

    Web Service Dilemma

    =?Utf-8?B?RGVtZXRyaQ==?=, Nov 29, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    305
    =?Utf-8?B?RGVtZXRyaQ==?=
    Nov 29, 2004
  4. Don Parker
    Replies:
    1
    Views:
    359
    Eliyahu Goldin
    Jan 20, 2005
  5. Ted Sung
    Replies:
    1
    Views:
    320
    Sherm Pendley
    Aug 30, 2004
Loading...

Share This Page