Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re^4: Summing numbers in a file

by jcb (Parson)
on Jun 01, 2020 at 02:39 UTC ( [id://11117541]=note: print w/replies, xml ) Need Help??


in reply to Re^3: Summing numbers in a file
in thread Summing numbers in a file

Do I misunderstand, or is the colliding file handle actually Foo::FH in the example? In this example, I would say that the problem is not the use of a global file handle, but the main script placing its code into package Foo and calling frobnicate incorrectly. The use of subroutine prototypes would either make the bug in frobnicate obvious or raise a compile-time error at line 18 when it is called with too many arguments.

I argue that lexical file handles are a neutral matter of style when they are declared at top-level (which is normally limited to the main script because modules typically provide subs but do not execute code upon loading). The real problem in the contrived example is calling a subroutine with the wrong number of arguments.

In a case where the file handle is intended to be an "environment parameter" to a subroutine, global file handles are the only option, but please do not actually do that in production code, or at least very clearly document routines that expect certain global file handles to be set up by their callers.

Replies are listed 'Best First'.
Re^5: Summing numbers in a file
by Athanasius (Archbishop) on Jun 01, 2020 at 07:37 UTC
    Do I misunderstand, or is the colliding file handle actually Foo::FH in the example?

    Yes, that’s correct. The example was intended to show a possible pitfall of using a package global variable instead of a lexical variable.

    In this example, I would say that the problem is not the use of a global file handle, but the main script placing its code into package Foo and calling frobnicate incorrectly. The use of subroutine prototypes would either make the bug in frobnicate obvious or raise a compile-time error at line 18 when it is called with too many arguments.

    Well, the idea was that the call to frobnicate was actually what was intended, but the implementation of the subroutine in Foo.pm was erroneous. So if prototypes were used, the sub might well have the correct prototype — sub frobnicate ($) — and then still fail without error or warning. (But anyone using prototypes is strongly advised to familiarize themselves with Far More than Everything You've Ever Wanted to Know about Prototypes in Perl -- by Tom Christiansen first.)

    But all this is a bit beside the point; I did say the example was “highly contrived.” :-) The point I was trying to make is that variables should — as a rule of good practice — be given the minimum scope needed, and no more.1 Think Defensive programming. Another important principle is this: Wherever possible, prefer compile-time errors to run-time errors.2 If you can make the compiler do your debugging for you, you’ll save both time and effort. So in the case under discussion, by limiting the scope of the filehandle variable you can harness the compiler to check for errors which you would otherwise have to hunt down yourself.

    In the end, as always in Perl, TMTOWTDI. But, what do you gain by using a package global variable for a filehandle where a lexical variable would do the same job?

    1I consider this a corollary of the Principle of least privilege, although strictly speaking that principle has a somewhat narrower focus.
    2This principle is set forth by Scott Meyers in one of his Effective C++ books; I don’t have the reference to hand.

    [As I was about to post this, I found that haukex had already made a similar case in his excellent reply Re^5: Summing numbers in a file. I’ll post mine anyway, but please read it in conjunction with the post by haukex.]

    Cheers,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Another important principle is this: Wherever possible, prefer compile-time errors to run-time errors.
      Indeed. Finding errors earlier rather than later is a sound general principle in any programming language: it's listed as general guideline number seven at On Coding Standards and Code Reviews, for example. Though more common in C++, this principle applies to Perl as well - after all, using strict catches many typos at compile time rather than run time. Other Perl examples could be given, such as a hash reference catching an odd number of elements in an anonymous hash at compile time - mentioned here and in "Use a hash of named arguments for any subroutine that has more than three parameters" in Perl Best Practices.

      As for who invented the find errors at compile time rather than run time meme, in addition to your citation of Scott Meyers in Effective C++, it's also listed as one of the 101 Guidelines in C++ Coding Standards by Alexandrescu and Sutter (2004), as described in this comparison of C++ Coding Standards with Perl Best Practices.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11117541]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (1)
As of 2024-04-19 18:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found