2

How to solve the following?

use 5.014;
use warnings;
use Test::Simple tests => 4;

ok( doit(0123)   == 83, "arg as octal number" );
ok( doit(83)     == 83, "arg as decimal number" );
ok( doit('0123') == 83, "arg as string with leading zero" );
ok( doit('123')  == 83, "arg as string without leading zero" );

sub doit {
    my $x = shift;
    return $x;                                     # how to replace this line
    #return  got_the_arg_as_string ? oct($x) : $x; # with something like this
}

E.g. If i pass to the doit sub any string - mean quoted value - (with or without the leading zero), it should be converted to octal value. Otherwise, it is just an number.

cajwine
  • 3,100
  • 1
  • 20
  • 41
  • 2
    Wondering why you want such interface, where the quoted and unquoted arguments behaves differently. For me this looks like an source of future bugs... – clt60 May 13 '16 at 13:07
  • @cajwine: that contradicts what you say in the question where you want doit('123') to be considered octal too ?? – ysth May 13 '16 at 14:18

1 Answers1

7

Perl's internal representation of a scalar may be as in integer or a string, and it remains ready to coerce that representation into any other scalar type at any moment. It is possible with C/XS code to get at a scalar's internal type. The JSON::XS module does this, for example, to decide whether a value should be rendered as a number or as a string.

Here's a proof of concept for your problem:

use Inline 'C';
sub foo {
    my ($x) = @_;
    print $x, " => isString: ", isString($x), "\n";
}
foo(0123);
foo('0123');

__END__
int isString(SV* sv)
{
    return SvPOK(sv) ? 1 : 0;
}

Program output:

83 => isString: 0
0123 => isString: 1

Related posts:

Difference between $var = 500 and $var = '500'

When does the difference between a string and a number matter in Perl 5?

Why does the JSON module quote some numbers but not others?

Update some of this functionality is exposed in the core B module, so no need to add as XS dependency:

use B;
sub isString {
    my $scalar = shift;
    return 0 != (B::svref_2object(\$scalar)->FLAGS & B::SVf_POK)
}
Community
  • 1
  • 1
mob
  • 117,087
  • 18
  • 149
  • 283
  • 2
    `sub isNumber { no warnings "numeric"; length($_[0] & "") }` – ysth May 13 '16 at 14:22
  • Ahh yes!!! The `use B` derived `isString` is *exactly* for what me looking. The @ysth 's `isNumber` works too, but the `isString` is nearly twice as fast. GREAT! thank you. ;) – cajwine May 14 '16 at 06:56
  • @ysth Could you please explain, ideally with an Answer that describes that method as an alternative. I understand the bitwise AND but I'm still not sure why it works. Thanks! – FlorianB Apr 08 '22 at 01:52
  • @FlorianB https://stackoverflow.com/a/3806159/17389 – ysth Apr 08 '22 at 14:26