Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Re^6: Summing numbers in a file

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


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

a module may load another module that may load another module that may do something that clashes with a global the main code is using; those issues are not fun to debug

Those issues are especially hard to debug because modules are not supposed to do that: each module should be in its own package (or be closely coordinated with any other components that share a package) and each package has its own "global" namespace, including bareword file handles. (But I have already said indirectly that modules should be using lexical file handles, except, for example, a logging module that opens the log file as a global handle in its package.)

"you don't need strict as long as you don't make typos"

Strictly, (pardon the pun) that is correct, but Murphy's Law says that the typo you do make will drive you crazy when it happens if you rely on that. :-)

you seem to be placing a lot of expectations on people to write correct code, when simply using lexical filehandles easily provides protection from the issues

As a polyglot programmer that often works in other languages that simply do not have those protective features (there is no "use strict" in Awk or Bourne-family shells, for two examples) I have come to see those expectations as routine because in languages that do not require variable declarations, they are.

I suspect that there is some limit of human attentiveness, such that a small set of "watch these carefully" is workable, but as that set expands, the risk of typos increases. In Awk or shell, this can effectively be an upper limit on the size of a program.

what do you mean with an "environment parameter"? And I very strongly disagree with "only option"

An implicit parameter passed via a variable with dynamic extent, such as a variable declared special in Common Lisp or a global variable in Perl. Such usage is rarely a good idea (at least in Perl), but can sometimes be necessary to work around badly-designed API limitations and pass needed information to a callback procedure, although a combination of closures and function currying might work in most cases, at the expense of being even harder to debug.

Replies are listed 'Best First'.
Re^7: Summing numbers in a file
by choroba (Cardinal) on Jun 02, 2020 at 08:52 UTC
    > there is no "use strict" in Awk or Bourne-family shells

    In larger bash scripts (which should be turned to Perl scripts, really) I always start with

    set -eu

    and put all code into a main() function, so that I can declare all variables with local. It's not as strict as strict, but it helps a lot.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re^7: Summing numbers in a file
by haukex (Archbishop) on Jun 02, 2020 at 22:00 UTC
    modules should be using lexical file handles, except, for example, a logging module that opens the log file as a global handle in its package

    Even there, a global filehandle is not necessary - a lexical declared in the module will do exactly the same job.

    I suspect that there is some limit of human attentiveness, such that a small set of "watch these carefully" is workable, but as that set expands, the risk of typos increases.

    Definitely - but this seems to be an argument for lexical filehandles rather than global ones.

    ... can sometimes be necessary to ... pass needed information to a callback procedure, although a combination of closures and function currying might work in most cases, at the expense of being even harder to debug.

    I disagree with these two bits - I think the usage of globals can be avoided 99.9% of the time (or more) through proper API design (and yes, I make the same exception for existing legacy APIs), and also I disagree with it being harder to debug; issues arising from incorrectly used globals are IMHO much more annoying to debug. But again, the problem usually arises more in larger programs rather than shorter ones.

      a global filehandle is not necessary - a lexical declared in the module will do exactly the same job

      My original argument was (intended to be) that global file handles and file-scope lexical file handles are equivalent, and the choice between them is a neutral matter of style.

      this seems to be an argument for lexical filehandles rather than global ones

      This comes back to a matter of style — for some programmers it may be such an argument, for others ALLCAPS tokens may be in a different "five, plus or minus two" from regular variables.

      I think the usage of globals can be avoided 99.9% of the time

      I agree that the use of globals generally should be minimized, but I consider file-scope lexicals (especially in the main script) a "sneaky" form of global variable. My concern is opposing unthinking "never use globals!" policies that then result in using file-scope lexicals in exactly the same way as globals — except that lexicals are harder to inspect.

      On a side note, a file-scope lexical can possibly have wider scope than a global if the same file defines multiple packages. Each global is contained in its package, but the lexical will persist across package statements to the end of the file.

      I disagree with it being harder to debug; issues arising from incorrectly used globals are IMHO much more annoying to debug

      File-scope lexicals effectively are globals, except that they are harder to inspect in the debugger. The "even harder to debug" remark was in reference to a "never use globals!" approach where the callback is wrapped in a closure that also carries references to lexicals in the block that will use it. The effect is global variables that are not actually in the symbol table, and (as far as I know) are almost impossible to debug because there is no way to look inside a closure.

        My original argument was (intended to be) that global file handles and file-scope lexical file handles are equivalent, and the choice between them is a neutral matter of style.

        But they're not equivalent, I've already named two disadvantages (no typo protection and potential clashes with other globals like package names), and I have yet to hear an advantage to bareword filehandles.

        Even in the limited case that you name (file-scope lexical file handles), there is yet another difference: if there ever is a clash in names, with lexicals it's incredibly easy to limit the scope of the issue: simply place the statements in a block, and you've limited the scope of the lexical, including a visual scope that allows one to glance at the code and know with certainty that this filehandle is contained within that scope. If one were using bareword filehandles instead, their scope is the entire package, beyond the bounaries of any blocks, so either you'd have to go through the entire package, renaming the filehandles to eliminate any name clashes, or you'd have to use bare blocks and the local *FH "hack", which has its own disadvantages. I see this as yet another disadvantage to bareword filehandles, again with no advantage.

        ... a file-scope lexical can possibly have wider scope than a global if the same file defines multiple packages ...

        That's true, but again easily solved by placing the package in a block, and Perl 5.14 introduced the package NAMESPACE BLOCK syntax to make this look even nicer. Some people even argue against multiple packages in one file. And even with the (admittedly sometimes confusing) issue of lexicals potentially crossing package boundaries, the scope of the lexical is still "visually" limited to the file; I would argue that name clashes because a global of the same name was used in a different file is a much more tricky issue.

        My concern is opposing unthinking "never use globals!" policies that then result in using file-scope lexicals in exactly the same way as globals ...

        Yes, a valid concern, but like you, I would argue that file-scope lexicals used in exactly the same way as globals are globals too. But that kind of dogmatic policy is not what I meant (or said). Instead, IMHO "globals can and should nearly always be avoided" is intended to cause people to think about what would be a better solution, which is usually a change in design.

        To someone who knows what they're doing, it may be acceptable to sometimes use globals, but again, this thread is in the context of giving advice to a beginner.

        ... (as far as I know) are almost impossible to debug because there is no way to look inside a closure.

        I'm far from an expert with the debugger, but that doesn't appear to be correct.

        $ cat x.pl use warnings; use strict; sub x { my $y = 123; sub { $y += shift; print "$y\n"; print shift->(), "\n"; } } my $z = x; my $foo = "abc"; $DB::single=1; $z->(111, sub { return $foo."def"; }); $ perl -d x.pl ... main::(x.pl:11): my $z = x; DB<1> c main::(x.pl:16): }); DB<1> s main::CODE(0x543ed97f20a0)(x.pl:6): 6: $y += shift; DB<1> y 0 $y = 123 DB<2> s main::CODE(0x543ed97f20a0)(x.pl:7): 7: print "$y\n"; DB<2> y 0 $y = 234 DB<3> s 234 main::CODE(0x543ed97f20a0)(x.pl:8): 8: print shift->(), "\n"; DB<3> s main::CODE(0x55d4d6a31da8)(x.pl:15): 15: return $foo."def"; DB<3> y 0 $foo = 'abc' $z = CODE(0x543ed97f20a0) -> &main::__ANON__[x.pl:9] in x.pl:5-9

Log In?
Username:
Password:

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

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

    No recent polls found