How does Perl decide to treat a scalar as a string or a number?

Consider the following code and its output:

Code
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my $HOURS_PER_DAY = 24.0 * 1.0;
my $BSA = 1.7 * 1.0;
my $MCG_PER_MG = 1000.0 * 1.0;
my $HOURS_DURATION    = 20.0 * $HOURS_PER_DAY;
my $dummy = $HOURS_PER_DAY * $BSA * $MCG_PER_MG * $HOURS_DURATION;
print Dumper($HOURS_PER_DAY);
print Dumper( $BSA);
print Dumper( $MCG_PER_MG);
print Dumper( $HOURS_DURATION );
Output
$VAR1 = 24;
$VAR1 = '1.7';
$VAR1 = 1000;
$VAR1 = 480;

As you can see, the second variable is treated as strings, while the first and the forth ones are treated as numbers. Anybody has any idea what is the underlying logic?

Edit arithmetic calculations that were added do not completely solve the problem (see the $BSA variable).


$ perl -v

This is perl, v5.10.0 built for cygwin-thread-multi-64int
(with 6 registered patches, see perl -V for more detail)

Copyright 1987-2007, Larry Wall

Answers


Data::Dumper's job is to serialize data and you can't tell much about what perl is doing internally with the data based on its output. The Devel::Peek module can dump the underlying flags and values stored in the variables. The Devel::Peek POD explains the significance of the flags.

#!/usr/bin/perl

use warnings;
use strict;
use Devel::Peek;

my $HOURS_PER_DAY = 24.0 * 1.0;
my $BSA = 1.7 * 1.0;
my $MCG_PER_MG = 1000.0 * 1.0;
my $HOURS_DURATION    = 20.0 * $HOURS_PER_DAY;
my $dummy = $HOURS_PER_DAY * $BSA * $MCG_PER_MG * $HOURS_DURATION;

Dump($HOURS_PER_DAY);
Dump($BSA);
Dump($MCG_PER_MG);
Dump($HOURS_DURATION);

__END__
SV = PVNV(0xd71ff0) at 0xd87f90
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,NOK,pIOK,pNOK)
  IV = 24
  NV = 24
  PV = 0
SV = PVNV(0xd71fc8) at 0xd87f60
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,NOK,pIOK,pNOK)
  IV = 1
  NV = 1.7
  PV = 0
SV = PVNV(0xd72040) at 0xd87f40
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,NOK,pIOK,pNOK)
  IV = 1000
  NV = 1000
  PV = 0
SV = IV(0xd8b408) at 0xd87f30
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 480
# compare the above output to output without the assignment to $dummy:
SV = IV(0x7b0eb8) at 0x7adf90
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 24
SV = NV(0x7c7c90) at 0x7adf60
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,NOK,pNOK)
  NV = 1.7
SV = IV(0x7b13d8) at 0x7adf40
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 1000
SV = IV(0x7b1408) at 0x7adf30
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 480

Your whole concept of Perl treating variables as strings or numbers is flawed. Perl will treat your variables the right way when you need it to, for example, arithmetic operators always take treat their argument as numbers (assuming you aren't abusing operator overloading or some such).

You shouldn't worry about this: Perl knows what it's doing.


Data::Dumper is using a simple pattern on the string representation of the variable to determine if it is a number. From the source code:

...
elsif ($val =~ /^(?:0|-?[1-9]\d{0,8})\z/) { # safe decimal number
  $out .= $val;
}
else {               # string
...

This doesn't match numbers that have a decimal point which explains the behavior you observed.


Quick dirty way to force a numeric context:

print Dumper( $HOURS_DURATION + 0.0 );

If your concern is how the data will be displayed then the clean way is:-

printf "%5.2d",$HOURS_DURATION;

Need Your Help

How does an Iterator throw ConcurrentModificationException on add

java iterator

How does Iterator throw ConcurrentModificationException when we are adding some object after current node or removing some object after current node. Does Iterator maintain a copy or reference to the

Unable to write URL to HREF Properly via hashchange

javascript jquery

I am trying to perform a document.write() to display a dynamic new.php HREF for each of the 3 conditions below (#pane1, #pane2, #pane3).