Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Math::BigInt doesn't grok "0 but true" #7232

Open
p5pRT opened this issue Apr 14, 2004 · 19 comments
Open

Math::BigInt doesn't grok "0 but true" #7232

p5pRT opened this issue Apr 14, 2004 · 19 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 14, 2004

Migrated from rt.perl.org#28538 (status was 'open')

Searchable as RT28538$

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2004

From zefram@fysh.org

Created by zefram@fysh.org

$ perl -MMath​::BigInt -we 'print Math​::BigInt->new("0"), "\n"'
0
$ perl -MMath​::BigInt -we 'print Math​::BigInt->new("0 but true"), "\n"'
NaN

Similar and probably related​:

$ perl -MScalar​::Util=dualvar -MMath​::BigInt -we 'print Math​::BigInt->new(dualvar(3, "foo")), "\n"'
NaN
$ perl -MScalar​::Util=dualvar -MMath​::BigInt -we 'print Math​::BigInt->new(dualvar(3, "5")), "\n"'
3

Looks like Math​::BigInt is examining the string value for validity
check, but then actually using the numeric value if it finds the string
sufficiently numeric. It really ought to be using looks_like_number.

Workaround for this problem involves avoiding implicit (unguarded)
conversions from scalar number to BigInt, which is theoretically simple
but a bit fiddly.

Perl Info

Flags:
    category=library
    severity=low

Site configuration information for perl v5.8.3:

Configured by Debian Project at Sat Mar 27 17:07:14 EST 2004.

Summary of my perl5 (revision 5.0 version 8 subversion 3) configuration:
  Platform:
    osname=linux, osvers=2.4.25-ti1211, archname=i386-linux-thread-multi
    uname='linux kosh 2.4.25-ti1211 #1 thu feb 19 18:20:12 est 2004 i686 gnulinux '
    config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN -Dcccdlflags=-fPIC -Darchname=i386-linux -Dprefix=/usr -Dprivlib=/usr/share/perl/5.8 -Darchlib=/usr/lib/perl/5.8 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.8.3 -Dsitearch=/usr/local/lib/perl/5.8.3 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl -Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Uusesfio -Uusenm -Duseshrplib -Dlibperl=libperl.so.5.8.3 -Dd_dosuid -des'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=undef use64bitall=undef uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O3',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -I/usr/local/include'
    ccversion='', gccversion='3.3.3 (Debian 20040314)', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=/lib/libc-2.3.2.so, so=so, useshrplib=true, libperl=libperl.so.5.8.3
    gnulibc_version='2.3.2'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic'
    cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:
    


@INC for perl v5.8.3:
    /etc/perl
    /usr/local/lib/perl/5.8.3
    /usr/local/share/perl/5.8.3
    /usr/lib/perl5
    /usr/share/perl5
    /usr/lib/perl/5.8
    /usr/share/perl/5.8
    /usr/local/lib/site_perl
    .


Environment for perl v5.8.3:
    HOME=/home/zefram
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/zefram/pub/i686-pc-linux-gnu/bin:/home/zefram/pub/common/bin:/usr/bin:/usr/X11R6/bin:/bin:/usr/local/bin:/usr/games:/opt/libunsn/bin
    PERL_BADLANG (unset)
    SHELL=/usr/bin/zsh

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2004

From perl_dummy@bloodgate.com

-----BEGIN PGP SIGNED MESSAGE-----

Moin,

Zefram wrote​:

# New Ticket Created by Zefram
# Please include the string​: [perl #28538]
# in the subject line of all future correspondence about this issue.
# <URL​: http​://rt.perl.org​:80/rt3/Ticket/Display.html?id=28538 >

This is a bug report for perl from zefram@​fysh.org,
generated with the help of perlbug 1.34 running under perl v5.8.3.

-----------------------------------------------------------------
[Please enter your report here]

$ perl -MMath​::BigInt -we 'print Math​::BigInt->new("0"), "\n"'
0
$ perl -MMath​::BigInt -we 'print Math​::BigInt->new("0 but true"), "\n"'
NaN

The doc from Math​::BigInt states​:

  Input
  Input values to these routines may be any string, that
  looks like a number and results in an integer, including
  hexadecimal and binary numbers.

I am responsible for the wording. What the wording means (and what I always
understood that it should mean) is that "0", "+0", "0.0", "0e1", ".0" etc
are all 0, but "0 but true" is not a number - unlike Perl, which simple
uses it as a numerical value when asked so​:

te@​null​:~> perl -wle 'print "0 but true" + 2'
2

However, I am amazed that "0 but true" is somehow "special"​:

te@​null​:~> perl -wle 'print "01 but true" + 2'
Argument "01 but true" isn't numeric in addition (+) at -e line 1.
3

(That just shows my lack of understanding of Perl internals and many nooks
and crannies. I am slightly aware that "0 but true" is used as return value
sometimes, but I am unsure why and when and where it will be treated
differently from "0".)

Similar and probably related​:

<$ perl -MScalar​::Util=dualvar -MMath​::BigInt -we 'print

Math​::BigInt->new(dualvar(3, "foo")), "\n"'
NaN
$ perl -MScalar​::Util=dualvar -MMath​::BigInt -we 'print
Math​::BigInt->new(dualvar(3, "5")), "\n"'
3

Looks like Math​::BigInt is examining the string value for validity
check, but then actually using the numeric value if it finds the string
sufficiently numeric. It really ought to be using looks_like_number.

Actually, BigInt checks the string value and then just hands the variable to
the lower lib, which deals with it. See​:

te@​null​:~> perl -MScalar​::Util=dualvar -MMath​::BigInt=lib,GMP -we 'print
Math​::BigInt->new(dualvar(3, "7")), "\n"'
7
te@​null​:~> perl -MScalar​::Util=dualvar -MMath​::BigInt -we 'print
Math​::BigInt->new(dualvar(3, "7")), "\n"'
3

While I agree these should be probably consistent, I really don't know how
to handle dual vars. (Never realized that these really exist...)

I mean, if the variable represents "3" and "foo" at the same time, how is
BigInt supposed to know which one is the *right* value? (The same goes for
"3" and "5", which one is right?)

One could also create an object that stringifies to something different than
it numifies.. which would also confuse BigInt...

Workaround for this problem involves avoiding implicit (unguarded)
conversions from scalar number to BigInt, which is theoretically simple
but a bit fiddly.

Just to clarify, do you mean workaround in your code, or in BigInt?

Thanx for your report, I would like to have some more info and input from
other people before I go and change something :)

Best wishes,

Tels

- --
Signed on Wed Apr 14 20​:10​:48 2004 with key 0x93B84C15.
Visit my photo gallery at http​://bloodgate.com/photos/
PGP key on http​://bloodgate.com/tels.asc or per email.

"We have problems like this all of the time," Kirk said, trying to
reassure me. "Sometimes its really hard to get things burning." --
http​://tinyurl.com/qmg5

-----BEGIN PGP SIGNATURE-----
Version​: GnuPG v1.2.2-rc1-SuSE (GNU/Linux)
Comment​: When cryptography is outlawed, bayl bhgynjf jvyy unir cevinpl.

iQEVAwUBQH2BY3cLPEOTuEwVAQGYsgf+M7FOr9MQBxn8i/mhkRiONsK4+eCILs7w
+JQTUQl2MObtSeCXQYdUHtEMTpgCw40WDelsVQyMwCQk2wZqfHgTkS6H9Mb9girL
AJwxYxPu/XXzmZj3OMPKvWMUzSjKuKrm+IKEnpDsfJevAqFhQsvp4/eD1c0rXMKf
06PvbhAyna0d1SguTkH/SJ/AUAr8Ihn5ytGEIRiOKBfIEQLnTHGkzEEo6tHvgGUg
QKOohuUmjooQFI682GOkDXU96CR1sKK+qa0VQM1dofsgEcQlhoPcj9+pDLdZjFuf
6lBbGSauM8aeFPKNTmECjGCGmIJS3Kxvu2KhnzxsBjVpHfnGYgIXiQ==
=0Qia
-----END PGP SIGNATURE-----

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2004

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2004

From tassilo.parseval@post.rwth-aachen.de

On Wed, Apr 14, 2004 at 08​:22​:19PM +0200 Tels wrote​:

Zefram wrote​:

# New Ticket Created by Zefram
# Please include the string​: [perl #28538]
# in the subject line of all future correspondence about this issue.
# <URL​: http​://rt.perl.org​:80/rt3/Ticket/Display.html?id=28538 >

This is a bug report for perl from zefram@​fysh.org,
generated with the help of perlbug 1.34 running under perl v5.8.3.

-----------------------------------------------------------------
[Please enter your report here]

$ perl -MMath​::BigInt -we 'print Math​::BigInt->new("0"), "\n"'
0
$ perl -MMath​::BigInt -we 'print Math​::BigInt->new("0 but true"), "\n"'
NaN

The doc from Math​::BigInt states​:

   Input
     Input values to these routines may be any string\, that
     looks like a number and results in an integer\, including
     hexadecimal and binary numbers\.

I am responsible for the wording. What the wording means (and what I always
understood that it should mean) is that "0", "+0", "0.0", "0e1", ".0" etc
are all 0, but "0 but true" is not a number - unlike Perl, which simple
uses it as a numerical value when asked so​:

te@​null​:~> perl -wle 'print "0 but true" + 2'
2

However, I am amazed that "0 but true" is somehow "special"​:

te@​null​:~> perl -wle 'print "01 but true" + 2'
Argument "01 but true" isn't numeric in addition (+) at -e line 1.
3

(That just shows my lack of understanding of Perl internals and many nooks
and crannies. I am slightly aware that "0 but true" is used as return value
sometimes, but I am unsure why and when and where it will be treated
differently from "0".)

"0 but true" is no different from, say, "0 and true" when it comes to
converting it to a number (it's 0 both times). The difference is that "0
but true" wont ever trigger a warning. This is intentional and you will
find this special case by grepping through the perl source.

<$ perl -MScalar​::Util=dualvar -MMath​::BigInt -we 'print

Math​::BigInt->new(dualvar(3, "foo")), "\n"'
NaN
$ perl -MScalar​::Util=dualvar -MMath​::BigInt -we 'print
Math​::BigInt->new(dualvar(3, "5")), "\n"'
3

Looks like Math​::BigInt is examining the string value for validity
check, but then actually using the numeric value if it finds the string
sufficiently numeric. It really ought to be using looks_like_number.

Actually, BigInt checks the string value and then just hands the variable to
the lower lib, which deals with it. See​:

te@​null​:~> perl -MScalar​::Util=dualvar -MMath​::BigInt=lib,GMP -we 'print
Math​::BigInt->new(dualvar(3, "7")), "\n"'
7
te@​null​:~> perl -MScalar​::Util=dualvar -MMath​::BigInt -we 'print
Math​::BigInt->new(dualvar(3, "7")), "\n"'
3

While I agree these should be probably consistent, I really don't know how
to handle dual vars. (Never realized that these really exist...)

I mean, if the variable represents "3" and "foo" at the same time, how is
BigInt supposed to know which one is the *right* value? (The same goes for
"3" and "5", which one is right?)

One could also create an object that stringifies to something different than
it numifies.. which would also confuse BigInt...

That's what dualvars usually do. A variable has such a split personality
whenever

  $var+0 ne $var;

Whether you give priority to the numerical or the string slot is a
semantic issue. Since Math​::BigInt->new takes a string as argument,
using the string slot would seem more plausible. Whichever way you do
it, it should be documented.

Tassilo
--
$_=q#",}])!JAPH!qq(tsuJ[{@​"tnirp}3..0}_$;//​::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
$_=reverse,s+(?&lt;=sub).+q#q!'"qq.\t$&amp;."'!#+sexisexiixesixeseg;y~\n~~dddd;eval

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2004

From @hvds

Tassilo von Parseval <tassilo.parseval@​post.rwth-aachen.de> wrote​:
:That's what dualvars usually do. A variable has such a split personality
:whenever
:
: $var+0 ne $var;

It isn't quite as simple as that​: I wouldn't call "00" a dualvar, even
though it satisfies the above inequality.

Perhaps C< $var + 0 != "$var" + 0 > would be an adequate test?

The canonical example of dualvars is of course $!.

For Math​::BigInt, if it is worth checking for such things at all, it
would probably make most sense to prefer the numeric value. However,
care needs to be taken not to end up getting perl's default coercion
for some number to big for it to represent - that would rather defeat
the point. However, default coercions never create a dualvar, so as
long as there is a reliable (and efficient) way to check for them,
no ambiguity should arise.

Hugo

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2004

From perl_dummy@bloodgate.com

-----BEGIN PGP SIGNED MESSAGE-----

Moin,

On Wednesday 14 April 2004 22​:20, Tassilo von Parseval wrote​:

On Wed, Apr 14, 2004 at 08​:22​:19PM +0200 Tels wrote​:

"0 but true" is no different from, say, "0 and true" when it comes to
converting it to a number (it's 0 both times). The difference is that "0
but true" wont ever trigger a warning. This is intentional and you will
find this special case by grepping through the perl source.

*sigh* another of these "special" cases in Perl. How should BigInt handle
this? I think it should be NaN.

Other modules have similiar "problems"​:

te@​null​:~> perl -MMath​::GMP -le 'print Math​::GMP->new("0 but true") + 1'
1
te@​null​:~> perl -MMath​::GMP -le 'print Math​::GMP->new("0 but true") + 2'
2
te@​null​:~> perl -MMath​::GMP -le 'print Math​::GMP->new("0but true") + 2'
2
te@​null​:~> perl -MMath​::GMP -le 'print Math​::GMP->new("01but true") + 2'
2
te@​null​:~> perl -MMath​::GMP -le 'print Math​::GMP->new("01but 3true") + 2'
2
te@​null​:~> perl -MMath​::GMP -le 'print Math​::GMP->new("NaN") + 2'
2
te@​null​:~> perl -MMath​::GMP -le 'print Math​::GMP->new("1") + 2'
3

Whatever BigInt should do, the current behaviour is quite old​:

# perl -IMath-BigInt-0.01/lib/ -MMath​::BigInt -lwe 'print
$Math​::BigInt​::VERSION'
0.01
# perl -IMath-BigInt-0.01/lib/ -MMath​::BigInt -lwe 'print
Math​::BigInt->new("0 but true")+9'
NaN

That's what dualvars usually do. A variable has such a split personality
whenever

$var\+0 ne $var;

Whether you give priority to the numerical or the string slot is a
semantic issue. Since Math​::BigInt->new takes a string as argument,
using the string slot would seem more plausible. Whichever way you do
it, it should be documented.

Ok. I prefer the string version, too.

(While that might cause problems with libraries that are confused by
dual-vars I think it can be worked around).

Cheers,

Tels

- --
Signed on Wed Apr 14 22​:44​:54 2004 with key 0x93B84C15.
Visit my photo gallery at http​://bloodgate.com/photos/
PGP key on http​://bloodgate.com/tels.asc or per email.

"Die deutsche Zensoren - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - Dummköpfe - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - -." Heinrich Heine

-----BEGIN PGP SIGNATURE-----
Version​: GnuPG v1.2.2-rc1-SuSE (GNU/Linux)
Comment​: When cryptography is outlawed, bayl bhgynjf jvyy unir cevinpl.

iQEVAwUBQH2kiXcLPEOTuEwVAQEZPwf/U7GHLA9URj+fAtRBpKFgfDGbMDczqq+x
ZSOvASwwnhsjncneaxHNbdqW08sMELPhkh3lLRTwElHQh9cSB4xuuIZ97c/NSmNq
uQrYocrxHLKTc6CvTxculdN6q+kavez01GaF6KSAwpK5xOKJzFtt1TImiqrEmgTy
ncABH+fVBNSB6FY12Mqt3XxM/ZzasqTCG6c47wKMSC6z8NUlWJG58oDOXs9JN4VJ
JUgPKpSMXvvpdPOpLYcjhFi0xQVlRDvNLwqZn19V9JTZrgsbq0Em7HQabAMKT2UI
7nsdQ08mtrmovEffM81RAZKSdNMX+ut5yyo8z7jF8Ymc+Qf7fEcfxw==
=mLug
-----END PGP SIGNATURE-----

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2004

From zefram@fysh.org

Incidentally, this bug is a duplicate of #28493. I screwed up in sending
the report. Since this one's seeing activity, someone please kill #28493.

Tels via RT wrote​:

I mean, if the variable represents "3" and "foo" at the same time, how is
BigInt supposed to know which one is the *right* value? (The same goes for
"3" and "5", which one is right?)

If you're treating it as a string -- which you are for validity testing
-- you should use the string slot. A dualvar simply has two different
values, and which value you get depends on what operation you subject
the value to. It's rarely correct to look at both slots, which is what
happened in the case I pointed out.

One could also create an object that stringifies to something different than
it numifies.. which would also confuse BigInt...

This is exactly the same issue.

If you want to be able to use a value as both a string and a number and
get consistent results, then do

  $value = "$value";

or

  $value = 0 + $value;

depending on which slot you want to take, to collapse it to an ordinary
value.

Just to clarify, do you mean workaround in your code, or in BigInt?

I meant in my code. I had code that added together ordinary Perl
integers and BigInts, using +, expecting to get a correct BigInt result.
Now I write "(0+$a) + $b" instead of "$a + $b" (where $a is an ordinary
integer and $b is a BigInt), because $a is actually the return value of
a function that returns zero as "0 but true".

I can see why a string-based BigInt constructor is necessary, but (a)
please make it consistently use the string slot and (b) we should also
have a number-based constructor, consistently using the number slot.
I also propose that the implicit conversions in the overloaded operators
should be number-based rather than string-based, so that things that
look like they treat values as numbers will in fact do so.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2004

From tassilo.parseval@post.rwth-aachen.de

On Wed, Apr 14, 2004 at 10​:00​:25PM +0100 hv@​crypt.org wrote​:

Tassilo von Parseval <tassilo.parseval@​post.rwth-aachen.de> wrote​:
:That's what dualvars usually do. A variable has such a split personality
:whenever
:
: $var+0 ne $var;

It isn't quite as simple as that​: I wouldn't call "00" a dualvar, even
though it satisfies the above inequality.

You are right. It's trickier than that.

Perhaps C< $var + 0 != "$var" + 0 > would be an adequate test?

That suffers from the same problem​:

  ethan@​ethan​:~$ perl -MScalar​::Util=dualvar
  $a = dualvar(0, "string");
  print $a + 0 == "$a" + 0;
  __END__
  1

The problem seems to be that a string often enough evaluates to 0 when
used in numerical context.

The canonical example of dualvars is of course $!.

For Math​::BigInt, if it is worth checking for such things at all, it
would probably make most sense to prefer the numeric value. However,
care needs to be taken not to end up getting perl's default coercion
for some number to big for it to represent - that would rather defeat
the point. However, default coercions never create a dualvar, so as
long as there is a reliable (and efficient) way to check for them,
no ambiguity should arise.

Which leads to the question what a reliable pure-Perl way of discovering
the dualvarness of a variable is. One probably needs to branch into XS
to do that and so there maybe should be a Scalar​::Util​::isdualvar()?

Tassilo
--
$_=q#",}])!JAPH!qq(tsuJ[{@​"tnirp}3..0}_$;//​::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
$_=reverse,s+(?&lt;=sub).+q#q!'"qq.\t$&amp;."'!#+sexisexiixesixeseg;y~\n~~dddd;eval

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2004

From zefram@fysh.org

Hugo van der Sanden via RT wrote​:

It isn't quite as simple as that​: I wouldn't call "00" a dualvar, even
though it satisfies the above inequality.

I'd say that that *is* a dualvar, just one that's unlikely to be
a problem. I recall "00" used to be used where "0 but true" is now.
I accept 0+$val ne $val for the definition of a dualvar.

But we shouldn't need to ask whether something is a dualvar. It should
never matter. In any particular context a value should be treated
as either a number or a string. If we want to be able to use either,
we should have distinct operators, a la == and eq.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2004

From @demerphq

I'd say that that *is* a dualvar, just one that's unlikely to be
a problem. I recall "00" used to be used where "0 but true" is now.
I accept 0+$val ne $val for the definition of a dualvar.

Doesnt that make virtually every string a dualvar?

Yves

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2004

From @JohnPeacock

Orton, Yves wrote​:

Doesnt that make virtually every string a dualvar?

Not unless the string has been used in a numeric context before​:

$ perl -MDevel​::Peek -e '$pv = "Test"; Dump $pv; $dv = 42; $dv = "HHGTTG"; Dump $dv;'
SV = PV(0x804d5d8) at 0x806572c
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x805f240 "Test"\0
CUR = 4
LEN = 5
SV = PVIV(0x804d9e8) at 0x80657a4
REFCNT = 1
FLAGS = (POK,pPOK)
IV = 42
PV = 0x805ede0 "HHGTTG"\0
CUR = 6
LEN = 7

John

--
John Peacock
Director of Information Research and Technology
Rowman & Littlefield Publishing Group
4501 Forbes Boulevard
Suite H
Lanham, MD 20706
301-459-3366 x.5010
fax 301-429-5748

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2004

From @demerphq

Orton, Yves wrote​:

Doesnt that make virtually every string a dualvar?

Not unless the string has been used in a numeric context before​:

$ perl -MDevel​::Peek -e '$pv = "Test"; Dump $pv; $dv = 42;
$dv = "HHGTTG"; Dump $dv;'
SV = PV(0x804d5d8) at 0x806572c
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x805f240 "Test"\0
CUR = 4
LEN = 5
SV = PVIV(0x804d9e8) at 0x80657a4
REFCNT = 1
FLAGS = (POK,pPOK)
IV = 42
PV = 0x805ede0 "HHGTTG"\0
CUR = 6
LEN = 7

I meant WRT Zefram's definition​:

  0+$val ne $val

Which means that

  0+"HHGTTG" ne "HHGTTG"

thus pretty much any string that matches \D (insert suitable handwaving
here) would be a dualvar based on his criteria.

Basically I was making this point as an addendum to Hugo saying that the
rules were more complicated than that.

Yves

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2004

From @JohnPeacock

Orton, Yves wrote​:

Basically I was making this point as an addendum to Hugo saying that the
rules were more complicated than that.

Doh, yes of course you were. The actual definition should be symbolically more
like​:

  IV != (IV*)PV
and/or NV != (NV*)PV

where that cast stands in for the actual conversion of slots involved.

John

--
John Peacock
Director of Information Research and Technology
Rowman & Littlefield Publishing Group
4501 Forbes Boulevard
Suite H
Lanham, MD 20706
301-459-3366 x.5010
fax 301-429-5748

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2004

From zefram@fysh.org

I still maintain that this discussion of identifying dualvars is
irrelevant to this bug report. But anyway, here's a function to play
with​:

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

sub classify($) {
  my($val) = @​_;
  # N.B.​: domain​: $val must be non-reference non-glob defined scalar
  no warnings "numeric";
  my $isnum = 0+$val eq $val;
  my $isstr = "$val" == $val;
  if($isnum && $isstr) {
  print "both normal number and normal string\n";
  } elsif($isnum) {
  print "normal number, stringification is lossy\n";
  } elsif($isstr) {
  print "normal string, numerification is lossy\n";
  } else {
  print "must be a dualvar\n";
  }
}

Try passing it the arguments

  123
  "123"
  "0123"
  12345678901234567890
  dualvar(1, "1")
  dualvar(1, "01")
  dualvar(1, "foo")

This function classifies scalars based on whether they could have
originated as an ordinary number or an ordinary string, or whether they
could only exist as dualvars. "could have originated as an ordinary foo"
== "is accurately described by its foo part alone". Many values, such
as the small integers, could originate both ways. This only looks at
the current Perl-visible behaviour of the value, and can't say anything
about how it was actually created.

The test that I earlier endorsed as testing for dualvarness is in
fact the test used here that determines whether a value is accurately
described by its numeric part alone (i.e., a dualvar is not accurately
described by its numeric part alone). That's pretty much my instinctive
view of a dualvar -- and yes, this includes most ordinary strings -- but
then I'm thinking mostly from the point of view of numeric operations.
I find dualvarness to be a somewhat fuzzy concept.

Side discovery​: Data​::Dumper doesn't handle dualvars. It should probably
use something like the above code to decide whether to emit a dualvar()
call. I'll take this up in a separate bug report.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Apr 29, 2012

From @Hugmeir

On Thu Apr 15 09​:51​:36 2004, zefram@​fysh.org wrote​:

I still maintain that this discussion of identifying dualvars is
irrelevant to this bug report. But anyway, here's a function to play
with​:

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

sub classify($) {
my($val) = @​_;
# N.B.​: domain​: $val must be non-reference non-glob defined scalar
no warnings "numeric";
my $isnum = 0+$val eq $val;
my $isstr = "$val" == $val;
if($isnum && $isstr) {
print "both normal number and normal string\n";
} elsif($isnum) {
print "normal number, stringification is lossy\n";
} elsif($isstr) {
print "normal string, numerification is lossy\n";
} else {
print "must be a dualvar\n";
}
}

Try passing it the arguments

123
"123"
"0123"
12345678901234567890
dualvar\(1\, "1"\)
dualvar\(1\, "01"\)
dualvar\(1\, "foo"\)

This function classifies scalars based on whether they could have
originated as an ordinary number or an ordinary string, or whether they
could only exist as dualvars. "could have originated as an ordinary foo"
== "is accurately described by its foo part alone". Many values, such
as the small integers, could originate both ways. This only looks at
the current Perl-visible behaviour of the value, and can't say anything
about how it was actually created.

The test that I earlier endorsed as testing for dualvarness is in
fact the test used here that determines whether a value is accurately
described by its numeric part alone (i.e., a dualvar is not accurately
described by its numeric part alone). That's pretty much my instinctive
view of a dualvar -- and yes, this includes most ordinary strings -- but
then I'm thinking mostly from the point of view of numeric operations.
I find dualvarness to be a somewhat fuzzy concept.

Side discovery​: Data​::Dumper doesn't handle dualvars. It should probably
use something like the above code to decide whether to emit a dualvar()
call. I'll take this up in a separate bug report.

-zefram

Looks like the discussion on this ticket petered out some years ago; As
of version 1.998, Math​::BigInt still doesn't grok "0 but true".

(Tangentially related, Data​::Dumper still doesn't understand dualvars.
Nowadays, I imagine that to detect one of those you could use B to get
the flags, and check if it's both p?POK and p?[IN]OK)

@p5pRT
Copy link
Author

p5pRT commented Apr 29, 2012

From @cpansprout

On Sun Apr 29 10​:13​:39 2012, Hugmeir wrote​:

(Tangentially related, Data​::Dumper still doesn't understand dualvars.
Nowadays, I imagine that to detect one of those you could use B to get
the flags, and check if it's both p?POK and p?[IN]OK)

But that alone would bring up many false positives.

I wouldn’t consider $x a dualvar after ‘$x = "3.0"; 0+$x’.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 29, 2012

From @doy

On Sun, Apr 29, 2012 at 11​:01​:25AM -0700, Father Chrysostomos via RT wrote​:

On Sun Apr 29 10​:13​:39 2012, Hugmeir wrote​:

(Tangentially related, Data​::Dumper still doesn't understand dualvars.
Nowadays, I imagine that to detect one of those you could use B to get
the flags, and check if it's both p?POK and p?[IN]OK)

But that alone would bring up many false positives.

I wouldn’t consider $x a dualvar after ‘$x = "3.0"; 0+$x’.

I think that just not looking at the p variants would fix that issue -
just look for things that are both POK and [IN]OK.

-doy

@p5pRT
Copy link
Author

p5pRT commented Apr 29, 2012

From @cpansprout

On Sun Apr 29 11​:27​:06 2012, doy@​tozt.net wrote​:

On Sun, Apr 29, 2012 at 11​:01​:25AM -0700, Father Chrysostomos via RT
wrote​:

On Sun Apr 29 10​:13​:39 2012, Hugmeir wrote​:

(Tangentially related, Data​::Dumper still doesn't understand dualvars.
Nowadays, I imagine that to detect one of those you could use B to get
the flags, and check if it's both p?POK and p?[IN]OK)

But that alone would bring up many false positives.

I wouldn’t consider $x a dualvar after ‘$x = "3.0"; 0+$x’.

I think that just not looking at the p variants would fix that issue -
just look for things that are both POK and [IN]OK.

Not so.

$ perl5.15.9 -e '$x = "3.0"; 0+$x; use Devel​::Peek; Dump $x'
SV = PVNV(0x802340) at 0x822330
  REFCNT = 1
  FLAGS = (IOK,NOK,POK,pIOK,pNOK,pPOK)
  IV = 3
  NV = 3
  PV = 0x301580 "3.0"\0
  CUR = 3
  LEN = 16

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 30, 2012

From @Hugmeir

On Sun, Apr 29, 2012 at 4​:29 PM, Father Chrysostomos via RT <
perlbug-followup@​perl.org> wrote​:

On Sun Apr 29 11​:27​:06 2012, doy@​tozt.net wrote​:

On Sun, Apr 29, 2012 at 11​:01​:25AM -0700, Father Chrysostomos via RT
wrote​:

On Sun Apr 29 10​:13​:39 2012, Hugmeir wrote​:

(Tangentially related, Data​::Dumper still doesn't understand
dualvars.
Nowadays, I imagine that to detect one of those you could use B to
get
the flags, and check if it's both p?POK and p?[IN]OK)

But that alone would bring up many false positives.

I wouldn’t consider $x a dualvar after ‘$x = "3.0"; 0+$x’.

I think that just not looking at the p variants would fix that issue -
just look for things that are both POK and [IN]OK.

Not so.

$ perl5.15.9 -e '$x = "3.0"; 0+$x; use Devel​::Peek; Dump $x'
SV = PVNV(0x802340) at 0x822330
REFCNT = 1
FLAGS = (IOK,NOK,POK,pIOK,pNOK,pPOK)
IV = 3
NV = 3
PV = 0x301580 "3.0"\0
CUR = 3
LEN = 16

Oh, my bad then. Guess that in the end you would have to check if the
contents of the PV slot differed from the [NI]V slot, which is pretty much
what the discussion in the ticket suggested. Doh!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants