Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl - Is this a bug with looks_like_number, or am I being a stupid person?

Tags:

perl

This code:

#!/usr/bin/perl -w

use strict;
use Scalar::Util qw(looks_like_number);

sub what_the_fudge {
    my $string = "foo 123 bar";
    if ($string =~ /foo (.+) bar/) {
        if (looks_like_number($1)) {
            print "$1 looks like a number\n";
        } else {
            print "$1 doesnt look like a number\n";
        }
    }
}

&what_the_fudge;
&what_the_fudge;
&what_the_fudge;

Displays this:

123 doesnt look like a number
123 looks like a number
123 looks like a number

Why does it fail to recognize it as a number the first time? =( This baffles me.

Some information about my environment:

OS: OSX 10.6.8

perl -e 'use Scalar::Util; print "$Scalar::Util::VERSION\n"' --> 1.19

perl -v --> This is perl, v5.10.0 built for darwin-thread-multi-2level (with 2 registered patches, see perl -V for more detail)

like image 469
James Avatar asked Dec 25 '22 22:12

James


1 Answers

It's a bug that was fixed in Scalar::Util 1.20. ("Handle overloaded and tied values" in the Changes file.)

The XS version of looks_like_number failed to handle magical arguments properly. Magic is what allows code to be called when certain operations are performed on a variable (such as fetching its value).

Solutions:

  • Upgrade to Scalar::Util 1.20 or higher.
  • Delete the compiled component of your Scalar::Util to force the use of the Pure Perl implementation which doesn't suffer from this problem.
  • Use looks_like_number("$1") which creates a non-magical copy of $1 with the right value.

1.19:

int
looks_like_number(sv)
        SV *sv
PROTOTYPE: $
CODE:
#if (PERL_VERSION < 8) || (PERL_VERSION == 8 && PERL_SUBVERSION <5)
  if (SvPOK(sv) || SvPOKp(sv)) {
    RETVAL = looks_like_number(sv);
  }
  else {
    RETVAL = SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK);
  }
#else
  RETVAL = looks_like_number(sv);
#endif
OUTPUT:
 RETVAL

1.21:

int
looks_like_number(sv)
    SV *sv
PROTOTYPE: $
CODE:
  SV *tempsv;
  if (SvAMAGIC(sv) && (tempsv = AMG_CALLun(sv, numer))) {
    sv = tempsv;
  }
  else if (SvMAGICAL(sv)) {
      SvGETMAGIC(sv);
  }
#if (PERL_VERSION < 8) || (PERL_VERSION == 8 && PERL_SUBVERSION <5)
  if (SvPOK(sv) || SvPOKp(sv)) {
    RETVAL = looks_like_number(sv);
  }
  else {
    RETVAL = SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK);
  }
#else
  RETVAL = looks_like_number(sv);
#endif
OUTPUT:
  RETVAL

Try this:

what_the_fudge("foo 123 bar");
what_the_fudge("foo baz bar");
what_the_fudge("foo 123 bar");

sub what_the_fudge {
    my $string = shift;

I haven't actually tried it, but you should get

Version of Scalar::Util: 1.19
doesnt look like a number
looks like a number
doesnt look like a number
like image 99
ikegami Avatar answered Feb 19 '23 09:02

ikegami