Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

Strict isn't strict enough

by davies (Parson)
on Dec 31, 2011 at 16:22 UTC ( #945750=perlquestion: print w/replies, xml ) Need Help??
davies has asked for the wisdom of the Perl Monks concerning the following question:

Long ago, I remember reading some definitions. From memory, they were:

  • Bug: An undocumented feature.
  • Feature: a documented bug. E.g. "It is a feature of DrossWorks that hitting the spacebar reformats your hard disc".
  • I thought I had found a bug, but it turns out that it is documented. I have two files.

    use strict; use warnings; use diagnostics; use slave; $slave::typo = "Hello world"; print "$slave::typo\n";

    use strict; use warnings; use diagnostics; package slave; 1;

    This surprised me by working when I expected a compile time error. The docs say (my italics):

    This generates a compile-time error if you access a variable that wasn't declared via our or use vars, localized via my(), or wasn't fully qualified.

    So it's a feature, not a bug, but it's not a feature I like, as I'm just as capable of making typos in fully qualified names as in unqualified names. I tried use dominatrix, but that failed. Is there anything that will report the use of undeclared fully qualified variable names?


    John Davies

    Replies are listed 'Best First'.
    Re: Strict isn't strict enough (stop it)
    by tye (Sage) on Dec 31, 2011 at 17:33 UTC

      Doctor, it hurts when I do this.

      Don't define interfaces that require using fully-qualified names. As you noted, documenting that your interface requires such just makes it a "feature" of your design instead of a bug in your bad design.

      package Slave; use strict; use Exporter qw< import >; use vars qw< @EXPORT_OK $type >; @EXPORT_OK = qw< $type >; # ... 1;
      use strict; use Slave qw< $typo >;
      use strict; use Slave qw< $type >; print $typo;

      - tye        

        An alternative to having export the variable would be to write a get/set wrapper for $Slave::type:

        package Slave; my $type; sub type(;$) { $type = shift if @_; $type } 1; package main; use strict; use Slave; Slave::type("FOO"); print Slave::type . "\n"; Slave::tpye("BAR"); # dies

        Or, if you're on Perl 5.6+ and don't care about supporting archaic versions of Perl (and you should rarely care about such things)...

        package Slave; my $type; sub type(;$) :lvalue { $type = shift if @_; $type } 1; package main; use strict; use Slave; Slave::type = "FOO"; print Slave::type . "\n"; Slave::tpye = "BAR"; # dies

        Thank you. I had thought of using Exporter, but the docs seemed to be pretty emphatic that variable names should not be exported, so I was using full qualification instead. If it's an appropriate technique despite the docs (or, conceivably, my misunderstanding of them), then I'll go ahead.


        John Davies

          "Don't poke yourself in the eye."
          "Doctor, it hurts when I slice through my eye with a chainsaw."

          Although the docs you linked to are a bit over-the-top (quite an unfortunate thing in such a core module), they make a good point:

          To provide the capability to set/get class-wide settings, it is best instead to provide accessors as subroutines or class methods instead.

          The docs said, "Don't do X, do Y instead" and you used them to justify, "Since I can't do X, I'll do W" where "W" is a much worse idea than "X".

          What you are doing is equivalent to having public attributes in a class. That makes for pretty bad class design (of course, some people have a hard time even conceiving of class design without the equivalent of public attributes; for example, take a critical look at Moose ;).

          I'll let you struggle with whether you should abandon exposing global variables for your interface and replace them with global subroutines instead. There can certainly be advantages to that. But I won't try to scare you into such a decision with over-the-top proclamations. "Trust me". (:

          - tye        

          ... the docs seemed to be pretty emphatic that variable names should not be exported, so I was using full qualification instead.

          But the variables the Exporter docs warn against exporting are package variables (AFAIU, the only variables that can be exported by the module in question), i.e., global variables, which are commonly acknowledged to have the potential "horrible effects at-a-distance" also referred to in the docs.

          Your OPed question seems to boil down to "How can I use global variables without endangering my sanity?". The generally accepted short answer is "You can't!". (Remember: There is no Sanity Claus.)

    Re: Strict isn't strict enough
    by BrowserUk (Pope) on Dec 31, 2011 at 16:38 UTC

      If you'd typed

      $slave::tyop = "Hello world"; print "$slave::typo\n";

      You'd've gotton 3 warnings:

      Name "slave::typo" used only once: possible typo at -e line 1 Name "slave::tyop" used only once: possible typo at -e line 1 Use of uninitialized value $slave::typo in print at -e line 1

      As is, you've used it twice and spelt it the same both times. That a pretty clear indication that you are doing it intentionally.

      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

      The start of some sanity?

        Agreed, but in more complicated code it may be the result of a single typo being cut & pasted. I have the scars.


        John Davies

          *ANYTHING* can be typoed, and then cut-and-pasted. If your coding style is to randomly hit the keyboard, and then ask perl whether you did a good job, don't expect use strict; to be a silver bullet.

          Perhaps you should replace /usr/bin/perl with

          #!/usr/bin/sh echo "Possible typo detected at line 1. Please fix." exit 1
          BTW, what should perl do if you did my $hwatever and then cut-and-pasted the $hwatever?
    Re: Strict isn't strict enough
    by Khen1950fx (Canon) on Dec 31, 2011 at 22:12 UTC

      It seems to me that there is some indirection happening here, so I took your and tested it against some of my favorite modules:

      #!/usr/bin/perl -l use warnings; use strict 'refs'; require qw(slave); no indirect 'fatal'; use Devel::SimpleTrace; use Devel::SummarizedWarnings; $slave::typo = "Hello, World!"; warn $slave; print pop(@Devel::SummarizedWarnings::LOGGED_WARNINGS) =~ /$slave/;
    Re: Strict isn't strict enough
    by sundialsvc4 (Abbot) on Jan 03, 2012 at 14:34 UTC

      Perhaps you can dream up the design of some new useful “Perl lint” tool . . . if you do so, please tell us all about it.   Otherwise, I am afraid that “Perl has many warts,” and one might opine that this is one of them.   (Every language has its own specific collection of ear-mites.)   Now, turn this discussion into something that all of us can actually use... dream up a useful-to-many-of-us solution tool.   Something so cool and pragmatically useful that none of us will be able to fathom how we ever lived without it.

    Log In?

    What's my password?
    Create A New User
    Node Status?
    node history
    Node Type: perlquestion [id://945750]
    Approved by BrowserUk
    Front-paged by Old_Gray_Bear
    and all is quiet...

    How do I use this? | Other CB clients
    Other Users?
    Others taking refuge in the Monastery: (5)
    As of 2017-11-19 09:30 GMT
    Find Nodes?
      Voting Booth?
      In order to be able to say "I know Perl", you must have:

      Results (278 votes). Check out past polls.