Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Backdating strict

by Bod (Parson)
on Nov 17, 2020 at 19:51 UTC ( [id://11123746]=perlquestion: print w/replies, xml ) Need Help??

Bod has asked for the wisdom of the Perl Monks concerning the following question:

Over in Re^2: Newline's creep in, while using Tie::File I asked what I though was simple question...
should use strict; always be used or are there circumstances when it makes sense not to use this pragma?

As is often the case, I didn't realise where this simple question would lead. Several clever Monks have shown me the wisdom of using this simple but powerful line in every script going forward. But that is going forward...

I have many, many lines of production code within lots and lots of scripts and none of them use strict; To be clear, all the code works well in that it does everything it is supposed to do consistently and within an acceptable time. Some of it is evolving, some is largely static and I do not see it being developed further.

So my question is, given that I see the value of use strict; going forward, what might I do with existing, working code. Is there any benefit to going back over working code, breaking it and having to repair it again to include this pragma?

I do have test environments so I would not have to break the code whilst it is in production!

Replies are listed 'Best First'.
Re: Backdating strict
by GrandFather (Saint) on Nov 17, 2020 at 20:20 UTC

    If you revisit the code for maintenance there is some argument for using that as an opportunity to roll in strictures. But it's a bang for buck thing. With modern editors that perform background syntax checking it's pretty quick to identify where variables need to be declared and fix that. Because declaration gives a defined scope for variables it can also be a good way to think about how the code works. So the process of declaring variables can actually make the maintenance task easier.

    If you have no other need to visit the code then generally it's best to leave it as is. Another reason to visit the code may be occasional flakiness. In that case adding strictures, especially warnings, is very compelling.

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

      With modern editors that perform background syntax checking...

      Ah yes!
      That could be another issue. I use TextPad and have done for the last couple of decades. Taking a look at Atom is on my ToDo List but should I be looking at anything else?

      I fear I might be opening a can of worms here

        I've used Komodo IDE for many years. It's editor engine is the same engine used for Sublime Text so there is a lot of feature cross over in the editors. When I'm developing Perl code I pretty much never leave Komodo. It's debugger support is great and the IDE integrates well with test and coverage tools. Common revision control systems are well supported. And these days it is essentially free, although if you are doing a lot of script coding it was worth the price of admission even when it was a pay for product.

        Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

        An editor war? Why not? ;) Seriously though, Notepad++ is great, or Vim has Windows builds.

        While we are making editor suggestions, I find GNU Emacs and its cperl-mode to be very useful for writing Perl code.

        "should I be looking at anything else?"

        I use intelliJ IDEA as my IDE, with the Camelcade Perl5 plugin, and Devel::Camelcadedb distribution which allows in-IDE debugging. Of course, I also have the Vim plugin installed in the IDE as well. Been using this setup for years. I've got their Open Source license, but the free version works all the same.

        Here's an image I saved quite some time ago.

Re: Backdating strict
by BillKSmith (Monsignor) on Nov 17, 2020 at 22:12 UTC
    If all that was required was to add the line use strict; to the top of your program, you would do it without asking our advice. Doing this, is going to create a huge number of error messages most of which refer to undeclared variables. You could declare these variables at the top of your file until all of these messages are satisfied. That would defeat the purpose of the change. It is unlikely that it would be of any help to anyone. Rethinking the scope requirements of every variable and declaring them appropriately is an error prone task that is probably more work than you are willing to take on. That only fixes "strict vars". If your code violates other restrictions, you could have much bigger problems. I recommend that all new code that you add should conform to strict, but the payback for fixing existing code is not worth the effort required.
    Bill

      You may well be right - and I see the redoubtable LanX agrees.

      It depends though on how the original code was written, especially with regard to variable scope. If the original code follows the four simple rules in the Encapsulation section at On Coding Standards and Code Reviews, namely:

      1. Avoid non-const global variables.
      2. Minimize the scope of variables, pragmas, etc..
      3. Minimize the visibility of variables.
      4. Don't overload variables with multiple meanings.
      you might be able to make the code strict-safe quicker than you think. Especially if it's already partitioned into modules with a unit test for each module.

      To prove my point, I remember once coming back to a large module I'd originally written, only to fall off my chair when I noticed some clown had commented out the use strict line at the top of the file! Without a comment to explain why. BTW, On Commenting Out 'use strict;' shows I'm not alone in being scarred for life by this unpleasant experience.

      Anyways, after picking myself up off the floor, I was pleasantly surprised to quickly repair this unfortunate act of code vandalism by restoring the use strict line and making only minor adjustments to the code. Admittedly, having the bulk of the code already strict-safe and having a unit test for the module certainly helped.

Re: Backdating strict
by eyepopslikeamosquito (Archbishop) on Nov 18, 2020 at 04:39 UTC

    To be clear, all the code works well in that it does everything it is supposed to do consistently and within an acceptable time ... I do have test environments so I would not have to break the code whilst it is in production!

    What is the current state of your code?

    • Roughly how many lines of code? Thousands? Millions?
    • Is it designed as a set of (loosely coupled) cohesive modules?
    • How well does it do information hiding?
    • Is it designed so that components can be easily tested in isolation?
    • How happy are you with your current interfaces?
    • Are you following a consistent error handling strategy? What is it?
    • Do you have unit tests? Do they test boundary conditions? Errors and exceptions?
    • Do you know what percentage of your code is covered by tests? (e.g. using Devel::Cover)

    The ideal is to gradually improve your code, one module at a time, always keeping a working system. Typically you would add use strict only when you need to change a module anyway and so need to retest it.

    Re when/if to rewrite working legacy code, I keep a long list of previous PM discussions on that tricky topic at: Re: Strategies for maintenance of horrible code? (Legacy Code References)

Re: Backdating strict
by dsheroh (Monsignor) on Nov 18, 2020 at 08:42 UTC
    Lots of good answers already, but there's one point I didn't see anyone else making already:

    strict is a lexical pragma.

    The practical significance of this is that you don't have to slap use strict at the top of your old code and swallow the whole elephant in one gulp. As you're revisiting your code to maintain or debug it, you can add strict one sub, or even just one block, at a time, gradually increasing the proportion of the code which is running under strict - and also limiting how much of it is broken at a time as you are in the process of improving it.

      I've hit a problem rather early on with use strict;!

      I am writing some code mostly to test a module I am writing for this purpose -> To Extend, to Use, to Create - of course, the new code has use strict; at the begining thanks to the good influence of the Monks...

      #!/usr/bin/perl use strict; require "incl/common.pl"; require "incl/html.pl"; my $update_time = $dbh->selectrow_array("SELECT NOW()");

      The problem I am getting is Global symbol "$dbh" requires explicit package name at eric.pl line 7. The variable $dbh is a database handle from DBD::mysql and it is defined in require "incl/common.pl"; without the my keyword.

      I have tried adding my $dbh; before the require statement thinking that I could simply declare the variable before assigning it within common.pl but that still gives Can't call method "selectrow_array" on an undefined value. As should be clear from the filename, common.pl is used by every script on the website so changing the way the database handle is declared and defined is not something I would want to do lightly...although I doubt anything untoward would happen I would rather know.

      Any thoughts on how I should proceed?

        ... $dbh ... is defined in require "incl/common.pl"; without the my keyword.

        Then it is a package-global variable. What namespace (package) does incl/common.pl use? If there is no explicit package statement in the required file, I believe it will be in the default main package (update: or whatever package is active in the file into which incl/common.pl is required). So, try
            my $update_time = $main::dbh->selectrow_array("SELECT NOW()");
        i.e., use the fully qualified variable name.

        Also, $::dbh is shorthand for $main::dbh.


        Give a man a fish:  <%-{-{-{-<

Re: Backdating strict
by LanX (Saint) on Nov 17, 2020 at 20:19 UTC
    I don't think there is a general answer which applies everywhere.

    I too have old code written in my dark ages, which I never ported. (And contrary to you I already know the possible traps very well.)

    IMHO most needed refactoring will imply using explicit my and our declarations for your variables.

    I recommend you should make it a habit to write new code with strict and warnings to get used to it.

    After a while, maybe a year, you should re-evaluate if it's worth refactoring your old code.

    My 2˘

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

Re: Backdating strict
by bliako (Monsignor) on Nov 17, 2020 at 21:54 UTC
    To be clear, all the code works well in that it does everything it is supposed to do consistently and within an acceptable time. 

    Well, now-a-days program-testing is the judge for whether a program does what it is supposed to do. I am absolutely sure that in X years from now, what we today know as program testing will be frowned upon but until that time comes you probably must create hundreds of test-scripts to test the behaviour of your scripts under all real-world/user-input/network-state conditions. Did he enter X/Network failed/Sun collapsed? ooohhh I should have caught that. Bummer, test failed, back to the drawing room.

    Secondly, a program without use strict; will swallow a lot of bad behaviour and (Perl will) substitute with default actions. And two wrongs in this case can make a "good" or "pass" ... And this is a ticking bomb ready to explode...

    If your code is good, then adding use strict; should have no effect on its output, right?

      If your code is good, then adding use strict; should have no effect on its output, right?

      I didn't use the word "good" - I said it works...

      Some of the code that I wrote as recently as a year ago I look back on and think "did I really write that?". I guess that means that I am improving. As for code I wrote 2 decades ago...well...we won't go there eh?

Re: Backdating strict
by ikegami (Patriarch) on Dec 01, 2020 at 09:00 UTC

    People have mentioned you can avoid going all in by enabling strictures in only some blocks of code at a time. But I don't see any mention of the ability of activating different strictures at different times.

    • You probably aren't violating use strict qw( subs );, so you could start by activating this globally. It only adds compile-time checks, so there's no worries about it finding errors you can't find with perl -c. And in the unlikely event that there happens to be violations, they are super easy to fix.

    • use strict qw( vars ); is the one that will probably result in the most work. It also gives the least value since it might not catch any "real" errors in working code. You can save this one for last, and it can easily be activated on a block-by-block basis. On the plus side, it only adds compile-time checks, so there's no worries about it finding errors you can't find with perl -c.

    • Maybe the stricture that will give you the most bang for the buck is use strict qw( refs );. Violations of this one can be really insidious. Such violations critically need fixing. On the down side, use strict qw( refs ); adds run-time checks, so you have to thoroughly test your code after enabling them.

Re: Backdating strict
by perlfan (Vicar) on Nov 18, 2020 at 19:50 UTC
    > Is there any benefit to going back over working code, breaking it and having to repair it again to include this pragma?

    Yes. If you have a pesky block that you can't "fix" then use a lexical block scope to turn off strict where needed.

      The inverse is true too.

      If you've got a long script and you don't feel ready to convert the whole thing over to strict, you can switch it on for a particular sub:

      sub do_stuff { use strict; ...; }

      If your script is working fine as-is, leave it alone. If you notice a bug in a sub or need to add a new feature to a sub, then switch on strict for just that sub while you're making your improvements, and then leave it on for that sub. Over time, more and more of your script will become strict. Once most of the file seems to be strict, then making the whole file strict will be a much smaller task.

        That does sound like the best way forward for me...enforce strict initially one subroutine at a time then one lexical block at a time until the complete code unit has strictures enforced.

        Quick question...
        If I have use strict; followed by a require statement in the same block, does the code that is brought in by the require have strict applied to it - my guess is yes as it is in the same lexical block.

        I can't test it right now as I am using my mobile and AFAIK there isn't a version of Perl for Android.

        then switch on strict for just that sub while you're making your improvements

        I suppose that use strict; makes the reset keyword obsolete.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11123746]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (5)
As of 2024-04-24 11:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found