ajwood
ajwood

Reputation: 19037

Side-effect of Perl's print function

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?

Upvotes: 4

Views: 281

Answers (1)

ikegami
ikegami

Reputation: 386256

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.

Upvotes: 9

Related Questions