Search code examples
perl

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


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!)


Solution

  • 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 "\\"