http://qs321.pair.com?node_id=408607

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

I'm trying to come up with some code to detect if a scalar variable contains a number or string. The difficulty is that I want to detect objects which have the appropriate conversion and comparison operators overloaded.

The reason is that it's common to insist that certain values be strings or numbers, but checks for them that rule out references will rule out objects that have numberlike or stringlike behaviour (such as BigInts or custom classes). So I want to know that references (blessed things) refer to objects which act just like numbers or strings.

This turns out to be not-so-simple for the case of numbers.

According to the perlfunc manpage on sort, I should be able to use <=> to compare things, and if it's NaN, it turns out undefined. I think the page is outdated. The following turns out true in ActiveState Perl Build 810 (Perl 5.8.4):

$a = 'string'; if (defined ($a <=> $a)) { print "Oops"; }

The == operator also seems to work for NaNs (Not-a-Numbers) when it's not supposed to.

I do know there's been discussions/complaints in the past about how bad it is when Perl distinquishes between == and eq (and found this frustrating when I was a Perl newbie...) but the docs should have been updated if this was changed. Was it changed???

Furthermore, I seem to have run into the following hiccup from overload:

package Foo; use overload '0+' => \&as_num; sub new { my $class = shift; my $self = { value => shift }; bless $self, $class; } sub as_num { my $self = shift; return $self->{value}; } package main; my $x = new Foo(3); my $z = (0+$x); # $x+0 also produces error

I run this and get the following error: "Operation `+': no method found, left argument has no overloaded magic, right argument in overloaded package Foo at bug.pl line 22."

This is based on a section from the cookbook in the overload manpage!

So my attempts to detect if 0+$num do not work.

To add to this, it seems that the looks_like_number function in the Scalar::Util module is broken, in that it says some references are numbers:

use Scalar::Util 'looks_like_number'; my $a = [ ]; my $h = { }; print looks_like_number($a), "\n"; print looks_like_number($h), "\n";

The code I was experimenting with was the following:

sub _numberlike { return 1, unless defined $_[0]; # L<perlfunc> manpage notes that NaN != NaN, so we can verify that # numeric conversion function works properly along with the # comparison operator. no warnings; return 1 if ((!ref $_[0]) || blessed($_[0])) && eval { ((0+$_[0]) == (0+$_[0])) && (($_[0] <=> $_[0])==0) }; return; }

In case you're interested, the "stringlike" function I have (which seems to work) is:

sub _stringlike { return 1 unless defined $_[0] && ref $_[0]; return 1 if (blessed $_[0]) && eval { (("$_[0]" eq "$_[0]") && (($_[0] cmp $_[0])==0)) }; return; }

To explain how these work, I am checking that the appropriate number/strong conversions work, and that the comparison operators work. Overload is supposed to create the less than/greater than variations from the comparison operators. For my purposes, these are all that I need to check for.

Also.... you might recognize this issue from some posts of mine on the module-authors list.