Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Side-effect of Perl's print function

Tags:

perl

I'm wondering why/how print in Perl can have a side-effect.

use Scalar::Util qw/looks_like_number/; 

my @A = (5, '2', 'aaa', 1, 'aab'); 

my @a = map { looks_like_number($_) } @A; 
print "1) @a\n";
# prints "4352 1 0 4352 0"

print "A print with a side-effect: @A\n";

@a = map { looks_like_number($_) } @A; 
print "2) @a\n";
# prints "1 1 0 1 0"

In this example, looks_like_number returns 4352 1 0 4352 0 before the print, and 1 1 0 1 0 after the print.

What does print do to these values to affect how they're interpreted by looks_like_number?

like image 988
ajwood Avatar asked Jan 11 '23 08:01

ajwood


1 Answers

When interpolating or otherwise concatenating a numeric value, a stringified version needs to be created. This string is stored within the scalar (in addition to the numeric value) for later use, and this can affect which value looks_like_number returns.


To inspect variables' internals, use Devel::Peek[1].

use Devel::Peek qw( Dump );
my @A = (5, '2', 'aaa');
Dump($_) for @A;  # Or: Dump(\@A);
print "@A\n";
Dump($_) for @A;

With Perl 5.20, you get the following: (Rerranged for readability)

Before                             After
===============================    ===============================
SV = IV(0x4532a78) at 0x4532a88    SV = PVIV(0x45563a0) at 0x4532a88
  REFCNT = 2                         REFCNT = 2
  FLAGS = (IOK,pIOK)                 FLAGS = (IOK,POK,pIOK,pPOK)
  IV = 5                             IV = 5
                                     PV = 0x454a870 "5"\0
                                     CUR = 1
                                     LEN = 10

SV = PV(0x45336a0) at 0x4532c08    SV = PV(0x45336a0) at 0x4532c08
  REFCNT = 2                         REFCNT = 2
  FLAGS = (POK,IsCOW,pPOK)           FLAGS = (POK,IsCOW,pPOK)
  PV = 0x455cf00 "2"\0               PV = 0x455cf00 "2"\0
  CUR = 1                            CUR = 1
  LEN = 10                           LEN = 10
  COW_REFCNT = 1                     COW_REFCNT = 1

SV = PV(0x4533720) at 0x4550b90    SV = PV(0x4533720) at 0x4550b90
  REFCNT = 2                         REFCNT = 2
  FLAGS = (POK,IsCOW,pPOK)           FLAGS = (POK,IsCOW,pPOK)
  PV = 0x455f210 "aaa"\0             PV = 0x455f210 "aaa"\0
  CUR = 3                            CUR = 3
  LEN = 10                           LEN = 10
  COW_REFCNT = 1                     COW_REFCNT = 1

Look at the FLAGS. When provided a number, the stringification of the number is cached (stored in the scalar) for future use. This is the side-effect mentioned.

The value returned by looks_like_number is sometimes a subset of the bits of FLAGS[2]. This is why the specific value returned varies. It will still return true if it returned true before, and it will still return false if it returned false before.


  1. illguts provides information on the format of scalars.

  2. See Behavior of Scalar::Util's looks_like_number.

like image 136
ikegami Avatar answered Jan 22 '23 10:01

ikegami