in reply to Re^3: Which "use" statements in a module do "bubble up" to the callers?
in thread Which "use" statements in a module do "bubble up" to the callers? [SOLVED]

Although the actual problem has been solved for me, one additional quick question:

You have mentioned "use open ..." as an alternative to "binmode(...)". But as far as I have understood the documentation, "use open ..." is lexically scoped as well, while "binmode(...)", when being at the beginning of a module which is used by a script, will set the file encoding throughout the whole script.

So in my case it would not be wise to switch from "binmode(...)" to "use open ...". Did I get this right?

Best regards,

Nocturnus

  • Comment on Re^4: Which "use" statements in a module do "bubble up" to the callers?

Replies are listed 'Best First'.
Re^5: Which "use" statements in a module do "bubble up" to the callers?
by choroba (Cardinal) on Sep 01, 2017 at 09:15 UTC
    If you use use open at the file scope, it will be lexically scoped to the whole file, too.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re^5: Which "use" statements in a module do "bubble up" to the callers?
by haukex (Archbishop) on Sep 01, 2017 at 12:23 UTC
    "use open ..." is lexically scoped as well

    This one is a bit tricky, but the answer turns out to be no, use open qw/:std :utf8/; has a global effect.

    If you read the documentation again, what it says is "Any two-argument open(), readpipe() (aka qx//) and similar operators found within the lexical scope of this pragma will use the declared defaults." But that's not what we're doing here, we're not trying to affect open calls, instead we're trying to change STD(IN|OUT|ERR), and the documentation about that says "The :std subpragma ... converts the standard filehandles (STDIN, STDOUT, STDERR) to comply with encoding selected for input/output handles" without mentioning lexical scope. So as it turns out, the effect of this pragma is actually global, as this quick test shows:

    sub pr { print join(",",@_,PerlIO::get_layers(*STDOUT), "\x{20AC}"),"\n" }
    BEGIN { pr(1); } pr(4);
    do {
    	use open qw/:std :utf8/;
    	BEGIN { pr(2); } pr(5);
    };
    BEGIN { pr(3); } pr(6);
    
    __END__
    
    Wide character in print at o.pl line 5.
    1,unix,perlio,€
    2,unix,perlio,utf8,€
    3,unix,perlio,utf8,€
    4,unix,perlio,utf8,€
    5,unix,perlio,utf8,€
    6,unix,perlio,utf8,€
    

    That warning comes from the very first pr(1); call, because afterwards the utf8 layer is added to STDOUT, and as you can see it stays active for the rest of the script regardless of lexical scope.

    Even if the :std option of the open pragma were to be lexically scoped, what I understand choroba is saying is that if you put the pragma at the top of the main file, it is effectively active for the entire run of the program as well (Update: not quite, see replies).

      Wow, that is tricky. Thank you very much!

      I would not have come to the idea that a pragma's subpragma might be scoped in another way than the pragma itself or its other subpragmas. That's the reason why I haven't found it in the documentation. But even if I had found it: IMHO, "... without mentioning lexical scope." for most people (including myself) implies "With this subpragma, nothing is different regarding the lexical scope from what has been said earlier in that text". This is very worrying and probably should be improved (to make myself clear: The Perl documentation is one of the best documentations I have ever seen, but even in the best documentation, there is always room for improvement).

      Finally, thinking about your last statement in your last comment took me quite a while, and I did some tests. If choroba really tried to say what you suspect, I think he is wrong:

      If I have a lexically scoped pragma at the top my main script, and if I then use another module, the pragma will not be in effect during initialization (i.e. during loading and compiling at compile time) of that other module. I can give a code example if I didn't manage to express clearly enough what I wanted to say.

      Thank you very much,

      Nocturnus

        I would not have come to the idea that a pragma's subpragma might be scoped in another way than the pragma itself or its other subpragmas.

        I agree the documentation could be clarified. A bit of historical perspective helps a little: In Perl things generally default(ed) to being global. For example, just like the open pragma, lexically-scoped warnings were introduced in 5.6.0 (before that it was just -w and $^W) - that may be 17 years ago now, but consider that was six years after the release of Perl 5 and nine years after Perl 4. And a lot of the wordings in the documentation haven't really changed over time (including open: this is from the first implementation in March 2000). So keeping in mind the default is "global", when you look at the documentation, it's fairly explicit about which part of use open is lexically scoped.

        If I have a lexically scoped pragma at the top my main script, and if I then use another module, the pragma will not be in effect during initialization (i.e. loading and compiling at compile time) of that other module.

        Yes, that's a good point! Update: Thinking about this a bit more, some more can be said about the particular current case. Your statement is correct for pragmas like warnings and the lexically-scoped part of the open pragma. But we're talking about STD(IN|OUT|ERR) here, these handles are global and normally stay opened during the entire run of the program, unless they are explicitly changed. That means you'd have to execute code every time the lexical scope changes, but the only mechanism built in to Perl to support lexical scoping of pragmas, $^H and %^H (perlpragma), doesn't really support that directly (although it can be hacked in). So if you wanted to affect those filehandles with an effect in the lexical scope, I think you'd have to get pretty creative with modules like B::Hooks::EndOfScope. So it's not really too surprising that the open pragma isn't that advanced (although doing it for the current dynamic scope would probably be easier). Plus, what would be the use case of switching the handles's encodings mid-run? The terminal isn't going to change encodings all of a sudden, and most likely neither will files piped to and from Perl via the shell. So taking all that into account, it's not really surprising that the :std option is implemented to just globally change the handles.