Why does setting `*\` to a scalar (string) reference not result in auto printing

64 Views Asked by At

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 :(`

Try it online!

I'm wondering why setting *\ to a scalar reference (\"...") results in $\ not being correctly printed 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!)

1

There are 1 best solutions below

2
ikegami On BEST ANSWER

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.


  1. $ 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 "\\"