I've been recently playing around with a Perl answer to a restricted-source code-challenge question on the Code Golf and Coding Challenges stack and am stumped as to why some code that I expect to work, doesn't.
My example is trying to get output from a script when called with -p0513
, but is equivalent:
*_=\"this works!";
print; # outputs `this works!`
*\=\"this doesn't work :(";
print; # outputs `this works!` without `$\`
print$\; # outputs `this doesn't work :(`
I'm wondering why setting *\
to a scalar reference (\"..."
) results in $\
not being correctly print
ed after $_
, when setting it naturally (e.g. $\="test"
) does. $_
being set the same way (e.g. *_=\"test"
) doesn't seem to be affected.
I'm wondering if any Perl experts have any idea why this happens, and if there's a way I can use *\=\"..."
(leaving me a free _
to try and get a 7th output mechanism!)
If I understand correctly, you are asking why
perl -e'local *\ = \"!\n"; print "";'
outputs nothing given that
perl -e'local $\ = "!\n"; print "";'
outputs !␊
.
First, let's examine what *x = \$y;
does.
*x
is a typeglob, or glob for short. It's a symbol table entry. It's a structure that contains a number of pointers. One points to a scalar, one to an array, one to hash, one to sub, etc.
Absent a lexical (my
or our
) named $x
,
$x
is equivalent to
${ *x{SCALAR} }
This means it accesses the scalar pointed by the scalar slot of the glob named x
.
*x = \$y;
sets that scalar to be $y
, making these equivalent:
$x
${ *x{SCALAR} }
$y
If local *\ = \"!\n";
makes $\
equivalent to a scalar containing !␊
, why doesn't the program output !␊
?
Well, it must be that print doesn't use $\
. And that is indeed the case.
Normally, $\
is a magical variable.[1] Setting it causes an internal variable to be set. Reading it causes an internal variable to be read. This internal variable is what print
uses.
You made it so $\
accesses a literal constant instead of the magic variable. The internal variable was never changed. So the output of print
is untouched.
$ perl -MDevel::Peek -e'Dump( $\ )'
SV = PVMG(0x55e7a72d00e0) at 0x55e7a728c2d0
REFCNT = 1
FLAGS = (GMG,SMG) <-- Scalar has get magic & set magic
IV = 0
NV = 0
PV = 0
MAGIC = 0x55e7a729da30
MG_VIRTUAL = &PL_vtbl_sv
MG_TYPE = PERL_MAGIC_sv(\0)
MG_OBJ = 0x55e7a728c240
MG_LEN = 1
MG_PTR = 0x55e7a72c4170 "\\"