in reply to Carp: $! vs "$!" in croaking

One of the first things Carp does is local($!, $^E), I assume because of what its documentation says: "Carp takes care not to clobber the status variables $! and $^E in the course of assembling its error messages." I think what's going on is that since @_ are aliases, this actually clears out the argument as well. Another thing to note is that $! is like a dualvar, though I'm not sure if this has to do with the issue. <update> Actually, in the following, $? behaves the same way as $!, while $@, an our variable, and an explicitly created dualvar do not - so it probably does have to do with the variable's magic in combination with local instead. </update> I suspect you'll have to work with "$!". This reproduces the issue:

use warnings; use strict; use Data::Dump; sub foo { dd @_; local $!; dd @_; } $! = 2; foo($!); $! = 2; foo("$!"); __END__ "No such file or directory" "" "No such file or directory" "No such file or directory"

Replies are listed 'Best First'.
Re^2: Carp: $! vs "$!" in croaking (updated)
by ikegami (Patriarch) on Jun 26, 2023 at 15:21 UTC

    I think what's going on is that since @_ are aliases, this actually clears out the argument as well.

    That would be the behaviour you'd get if local simply backed up the current value of a variable and restored it on scope exit.

    As you discovered, that's not what local does. Instead, it creates a new variable, aliases the name to the new variable, and aliases the name back to the original variable on scope exit.

    $ perl -e' use feature qw( say ); say 0+\$x; { local $x; say 0+\$x; } say 0+\$x; ' 94031376424552 94031376229560 94031376424552

    That means the fact that $_[0] is an alias for the localized variable shouldn't matter. And it normally doesn't.

    $ perl -e' use feature qw( say ); $x = 2; say 0+\$x; say $x; sub { local $x = 3; say 0+\$x; say $x; say $_[0]; }->( $x ); say 0+\$x; say $x; ' 94300947464040 Address of pre-local $x 2 Value of pre-local $x 94300947268840 Address of post-local $x 3 Value of post-local $x 2 Value of pre-local $x 94300947464040 $x is restored 2 Value of pre-local $x

    But $! is magical. And more specifically, it's a proxy for a C variable. local copies the magic onto the new scalar it creates. So you end up with two variables (the $! passed as argument and the new $! created by local) which both use the same C variable for storage.

    $ perl -e' use feature qw( say ); $! = 2; say 0+\$!; say 0+$!; sub { local $! = 3; say 0+\$!; say 0+$!; say 0+$_[0]; }->( $! ); say 0+\$!; say 0+$!; ' 93839899443048 Address of pre-local $! 2 Value of pre-local $! (aka value of errno) 93839899247848 Address of post-local $! 3 Value of post-local $! (aka value of errno) 3 Value of pre-local $! (aka value of errno) 93839899443048 $! is restored 3 Value of pre-local $! (aka value of errno)

    The net effect is that local $! doesn't really localize $! at all!

    $? is similarly a proxy for a C variable. $@ isn't magical.

      Accidentally submitted parent very early in its composition. (Mid sentence, even!) It has been heavily edited.

Re^2: Carp: $! vs "$!" in croaking
by cavac (Prior) on Jun 26, 2023 at 09:46 UTC

    Grumble. I feared that it's something i couldn't blame Carp for. Oh well, i'll spend a couple of hours writing a Perl script that audits and fixes all my other Perl scripts and modules to make sure arguments to croak() are quoted properly.

    Hmm, i could either modify an existing script (which probably has all the crud from the last 12 years) or ask ChatGPT to do it (and fix all the variable names and regular expressions). I could also write from scratch, but it's Monday and i'm not feeling THAT enthusiastic about fixing some error message handling...

    PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP