Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the autobox CPAN distribution.

Report information
The Basics
Id: 46814
Status: resolved
Priority: 0/
Queue: autobox

People
Owner: CHOCOLATE [...] cpan.org
Requestors: tyemq [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 2.55
Fixed in: (no value)



Subject: Please prefer "INTEGER" over "FLOAT"
Boolean values are considered of type FLOAT, which is likely surprising to many. Also, some numbers that are considered FLOAT would be better to consider as INTEGER. (I was curious whether Boolean values would be treated as STRING or INTEGER so I tested and was reminded that PL_sv_no and PL_sv_yes have not just PV and IV pre-filled, but also NV -- I also tested $! and found it of type STRING, which seems best). I wasn't surprised that autobox chose to pay attention to SV_NOK before the PV and IV equivalents (I presume). But the result in the case of Boolean values is unfortunate. And after some extensive experimenting, I think autobox should actually look at SV_IOK before SV_NOK. First, since so many built-ins return Boolean values (and I work with a lot of code that explicitly Booleanizes values via !!), it seemed reasonable to consider autobox trying to special-case them. I'd be fine with type(!!0) and type(!!1) returning "INTEGER" but would probably prefer a new type of "BOOL" just for them. Unfortunately, PL_sv_no and PL_sv_yes mostly get copied so the only way to detect a "Boolean value" would be to look at the values stored in the SV. This can be done tolerably well for PL_sv_no. Unfortunately, a copy of PL_sv_yes looks exactly like the following quite unBoolean SVs: #!/usr/bin/perl -wl use strict; use autobox::universal 'type'; use Devel::Peek 'Dump'; my $s= ''; my $i= 1; print type($i); # INTEGER if( $i*1.5 == 1.5 ) { $s .= "$i is 1.0"; } # Now $i is "identical" to a copy of PL_sv_yes Dump( $i ); my $f= 1.0; print type($f); # FLOAT if( $f & 1 ) { $s .= "odd $f"; } # Now $f is "identical" to a copy of PL_sv_yes Dump( $f ); my $true= !0; Dump( $true ); While experimenting with lots of cases related to this, I came to realize that looking at SV_IOK before SV_NOK probably produces better results. First, a tangential case to warm up: #!/usr/bin/perl -wl use strict; use autobox::universal 'type'; my $s= 'string'; print type($s); # STRING (good) print type(0+$s); # INTEGER (good) print type($s); # FLOAT (ugh) It seems like a (long-standing) bug that Perl sets SvIOK/SvNOK (not just SvIOKp/SvNOKp) in the above case, but autobox.pm can't really do anything about that (other than file a bug against Perl and hope). It is my expectation that Perl should only set SvIOK and/or SvPOK if $s looks_like_number() of the appropriate type. Or, perhaps autobox could have an option to check looks_like_number() when given an SV with both SvPOK and ( SvIOK or SvNOK ) where the distinction would matter? Maybe it could even unset SvPOK/SvIOK if it doesn't looks_like_number() to save time the next time. Well, I'd rather "fix" Perl (but expect eventually some reason to surface as to why things are this way, despite not being able to find one after consulting some true experts). Now let's hypothesize that I defined new_type() that acts how I'd like autobox's type() to behave (it checks SvIOK before SvNOK). #!/usr/bin/perl -wl use strict; use autobox::universal 'type'; use Devel::Peek 'Dump'; my $f= 1.5; print type($f); # FLOAT (good) print type(0&$f); # INTEGER (good) print type($f); # FLOAT (good) Dump( $f ); # Note that IOK is *not* set, just pIOK # new_type($f) would still be "FLOAT" (good) #!/usr/bin/perl -wl use strict; use autobox::universal 'type'; use Devel::Peek 'Dump'; my $f= 1.0; print type($f); # FLOAT (good) print type(0&$f); # INTEGER (good) print type($f); # FLOAT (fine) Dump( $f ); # Note that IOK *is* set, not just pIOK # new_type($f) would be "INTEGER", which seems okay #!/usr/bin/perl -wl use strict; use autobox::universal 'type'; use Devel::Peek 'Dump'; my $i= 1; print type($i); # INTEGER (good) print type(int($i/3)); # INTEGER (fine) print type($i); # FLOAT (Hrm!) Dump( $i ); # new_type($f) would be "INTEGER", which seems better So needing the integer part of an NV wouldn't make my proposed version of autobox treat the number as an INTEGER unless the NV has no fractional part. But doing a floating-point computation with an IV makes the current version of autobox treat it as a FLOAT from then on (footnote). I was a bit surprised how easy it was to get Perl to compute the NV for an IV. (footnote: Unless the IV is too large to fit with full precision in the NV, which can happen with 64-bit IVs if NVs aren't "long double".) And looking at SvIOK first would also make Boolean values INTEGER, which seems acceptable given how they are closest to the values 0 and 1 (and defining a "BOOL" type seems doomed). Thank you.
Many thanks for this detailed rationale. This should be fixed in autobox 2.60. chocolateboy