misterperl has asked for the wisdom of the Perl Monks concerning the following question:

I have no explaination for this:
# math my $x = "016"; my $y=$x * 10; print "y=$y\n"; # eval $y = eval( "$x * 10" ); print "evalled 016 * 10 , y = $y\n"; # eval without leading zero $x = "16"; $y = eval( "$x * 10" ); print "evalled 16 * 10 , y = $y\n"; me@ramster:~/perl$ ./x.pl y=160 evalled 016 * 10 , y = 140 evalled 16 * 10 , y = 160
Why does eval( "$x * 10" ) yield different numbers depending on if $x has leading zeros? This is more than perplexing, it's astounding! (Perl 5.8.8 on linux)

Replies are listed 'Best First'.
Re: Leading Zeros confound eval() ?
by toolic (Bishop) on Jul 21, 2015 at 18:54 UTC
Re: Leading Zeros confound eval() ?
by Anonymous Monk on Jul 21, 2015 at 19:00 UTC

    Perl treats literal numbers differently from strings converted to numbers, and as others have said literals beginning with zero are octal numbers:

    $ perl -wMstrict -le 'print 0+"010"' 10 $ perl -wMstrict -le 'print 0+ 010 ' 8

    When you write my $x = "016"; $y = eval("$x * 10");, the $x is evaluated into the string before the eval and it is the equivalent of asking Perl to evaluate 016 * 10:

    $ perl -wMstrict -le 'my $x = "016"; print eval("$x * 10");' 140 $ perl -wMstrict -le 'print 016 * 10;' 140
      thank-you that explanation makes sense. Its a odd side-effect of eval, IMHO, but I see why it's working that way..

      Voted you a ++

        BTW, official Perl documentation on this is here. Another difference is that underscores are not handled when strings are converted to numbers:

        $ perl -wMstrict -le 'print 0+ 1_234 ' 1234 $ perl -wMstrict -le 'print 0+"1_234"' Argument "1_234" isn't numeric in addition (+) at -e line 1. 1
Re: Leading Zeros confound eval() ?
by Laurent_R (Canon) on Jul 21, 2015 at 18:57 UTC
    Any number starting with "0" within the code is considered to be octal.

      Yep, and it's easy to demonstrate...

      perl -e 'my %h = (09 => 9);' Illegal octal digit '9' at -e line 1, at end of line
Re: Leading Zeros confound eval() ?
by Anonymous Monk on Jul 21, 2015 at 18:55 UTC
    016 is an octal number
      thanks guys - I thought about OCTAL. But why does eval() treat the val as octal, but outside of eval() its decimal? Why are they different? Larry had a bad day? I can't think of a reason why Perl should work this way.

        misterperl:

        In your original code, you have:

        my $x = "016";

        If you leave the quotes out, it would be treated as an octal number. So in the perl source code 016 is an octal number. But when perl converts a string to a number, it doesn't perform any octal, binary or hexadecimal conversions. So this bit of code would treat it as a normal decimal number:

        $ perl -e 'my $x="016"+1; print $x,"\n"' 17 $

        When you use eval, you can treat a string as a bit of perl source code, so it will be treated as an octal number:

        $ perl -e 'my $x=eval "016"; print $x,"\n"' 14 $

        Update: I should've read the rest of the thread before replying, Anonymonk already said this.

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.

        In your test without eval, you executed $x * 10

        In your test with eval, you executed 016 * 10

        You got different results because you executed different code, not because you used eval. If you had executed the same code with the eval as without (e.g. if you had used eval( '$x * 10' )), you would have gotten the same result.

Re: Leading Zeros confound eval() ?
by hippo (Archbishop) on Jul 22, 2015 at 08:28 UTC

    This is string eval and that's the reason why string eval is considered bad practice (generally).

    $ cat x.pl #!/usr/bin/perl -Tw use strict; use warnings; my $x = "016"; my $y=$x * 10; print "y=$y\n"; $y = eval( "$x * 10" ); print "string eval evalled 016 * 10 , y = $y\n"; $y = eval { $x * 10; }; print "block eval evalled 016 * 10 , y = $y\n"; $ ./x.pl y=160 string eval evalled 016 * 10 , y = 140 block eval evalled 016 * 10 , y = 160

    Avoid string eval. The reasons why you see the numbers you do are well explained in the previous replies. Use block eval and the problem (the apparent inconsistency) disappears and you don't have to think about unexpected stringification.