Perl / perl5

đŸȘ The Perl programming language
https://dev.perl.org/perl5/
Other
1.9k stars 540 forks source link

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

Open p5pRT opened 20 years ago

p5pRT commented 20 years ago

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

Searchable as RT28538$

p5pRT commented 20 years ago

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 commented 20 years ago

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 commented 20 years ago

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

p5pRT commented 20 years ago

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+(?\<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval

p5pRT commented 20 years ago

From @hvds

Tassilo von Parseval \tassilo\.parseval@&#8203;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 commented 20 years ago

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 commented 20 years ago

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 commented 20 years ago

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@&#8203;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+(?\<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval

p5pRT commented 20 years ago

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 commented 20 years ago

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 commented 20 years ago

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 commented 20 years ago

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 commented 20 years ago

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 commented 20 years ago

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 commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

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!