Search code examples
perlperlguts

How can I make Perl store integers as numbers instead of strings?


I'm parsing many numbers from a text file into hash entries consisting of a key and corresponding reference to array of values. Using Devel::Peek and Devel::Size I noticed that the string representation of the numbers is stored along in this data structure, which wastes memory. How can I rid the memory of these string representations (in other words, how can I turn a PVIV into an IV)?


Solution

  • First of all, if you're trying to save memory at this level, Perl is probably not the tool for you. Perl wantonly "wastes" memory when it provides a speed benefit.

    $ perl -e'
       use feature qw( say );
       use Devel::Size qw( size );
    
       sub f {
          my $x;
          say size($x);
          $x = "x" x 100;
          say size($x);
       }
    
       f() for 1..2;
    '
    24
    134
    134
    134
    

    Both 0+$scalar and int($scalar) return a scalar of type SVt_IV or SVt_NV. Either of these will do.

    $ perl -e'
       use feature qw( say );
       use Devel::Size qw( size );
       my $x = 1234567890;
       my $y = "1234567890";
       say size($x);
       say size($y);
       say size($0+$y);
       say size(int($y));
    '
    24
    44
    24
    24
    

    It's not possible to downgrade an existing scalar, but you could replace it through "aliasing".

    $ perl -e'
       use feature qw( say );
       use experimental qw( refaliasing );
       use Devel::Size qw( size );
       my $x = 1234567890;
       my $y = "1234567890";
       say size($x);
       say size($y);
       \$y = \(0+$y);
       say size($y);
    '
    24
    44
    24