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

perl 5.8.x bug: overloaded 'eq' does not work with 'nomethod' #8784

Closed
p5pRT opened this issue Feb 19, 2007 · 6 comments
Closed

perl 5.8.x bug: overloaded 'eq' does not work with 'nomethod' #8784

p5pRT opened this issue Feb 19, 2007 · 6 comments

Comments

@p5pRT
Copy link

p5pRT commented Feb 19, 2007

Migrated from rt.perl.org#41546 (status was 'resolved')

Searchable as RT41546$

@p5pRT
Copy link
Author

p5pRT commented Feb 19, 2007

From @cpansprout

If a package uses overloading with the 'nomethod' symbol and the
'nomethod' subroutine is called when the 'eq' operator is used, the
return value gets negated. Furthermore, a warning is issued if the
return value is not numeric--but booleans should not have to be numeric.

This program prints 1, though it should print nothing​:
#!/usr/bin/perl -lw
use overload 'nomethod' => sub { return 0 };
print bless([], 'main') eq "oenthueonthu";

This program prints nothing, though it should print 1​:
#!/usr/bin/perl -lw
use overload 'nomethod' => sub { return 1 };
print bless([], 'main') eq "oenthueonthu";

And this program

#!/usr/bin/perl -lw
use overload 'nomethod' => sub { return 'something' };
print bless([], 'main') eq "oenthueonthu";

prints​:
Argument "something" isn't numeric in string eq at - line 3.
1


Flags​:
  category=core
  severity=low


Site configuration information for perl v5.8.8​:

Configured by neo at Tue Jan 9 16​:06​:53 PST 2007.

Summary of my perl5 (revision 5 version 8 subversion 8) configuration​:
  Platform​:
  osname=darwin, osvers=8.8.0, archname=darwin-thread-multi-2level
  uname='darwin treebeard.local 8.8.0 darwin kernel version 8.8.0​:
fri sep 8 17​:18​:57 pdt 2006; root​:xnu-792.12.6.obj~1release_ppc power
macintosh powerpc '
  config_args=''
  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 ='-g -pipe -fno-common -DPERL_DARWIN -no-cpp-
precomp -fno-strict-aliasing -I/usr/local/include',
  optimize='-O3',
  cppflags='-no-cpp-precomp -g -pipe -fno-common -DPERL_DARWIN -no-
cpp-precomp -fno-strict-aliasing -I/usr/local/include'
  ccversion='', gccversion='4.0.0 20041026 (Apple Computer, Inc.
build 4061)', gccosandvers='darwin8'
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=4321
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
  ivtype='long', ivsize=4, nvtype='double', nvsize=8,
Off_t='off_t', lseeksize=8
  alignbytes=8, prototype=define
  Linker and Libraries​:
  ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc', ldflags =' -L/usr/
local/lib'
  libpth=/usr/local/lib /usr/lib
  libs=-ldbm -ldl -lm -lc
  perllibs=-ldl -lm -lc
  libc=, so=dylib, useshrplib=false, libperl=libperl.a
  gnulibc_version=''
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
  cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup -L/
usr/local/lib'

Locally applied patches​:


@​INC for perl v5.8.8​:
  /usr/local/lib/perl5/5.8.8/darwin-thread-multi-2level
  /usr/local/lib/perl5/5.8.8
  /usr/local/lib/perl5/site_perl/5.8.8/darwin-thread-multi-2level
  /usr/local/lib/perl5/site_perl/5.8.8
  /usr/local/lib/perl5/site_perl
  /System/Library/Perl/5.8.6/darwin-thread-multi-2level
  /System/Library/Perl/5.8.6/darwin-thread-multi-2level
  /System/Library/Perl/5.8.6
  /Library/Perl/5.8.6/darwin-thread-multi-2level
  /Library/Perl/5.8.6/darwin-thread-multi-2level
  /Library/Perl/5.8.6
  /Library/Perl
  /Network/Library/Perl/5.8.6/darwin-thread-multi-2level
  /Network/Library/Perl/5.8.6
  /Network/Library/Perl
  /System/Library/Perl/Extras/5.8.6/darwin-thread-multi-2level
  /System/Library/Perl/Extras/5.8.6/darwin-thread-multi-2level
  /System/Library/Perl/Extras/5.8.6
  /Library/Perl/5.8.1
  .


Environment for perl v5.8.8​:
  DYLD_LIBRARY_PATH (unset)
  HOME=/Users/neo
  LANG (unset)
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/bin​:/sbin​:/usr/bin​:/usr/sbin​:/usr/TeX/bin/powerpc-
darwin6.8​:/usr/local/bin
  PERL_BADLANG (unset)
  SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Feb 21, 2007

From rick@bort.ca

On Feb 19 2007, Father Chrysostomos wrote​:

This program prints 1, though it should print nothing​:
#!/usr/bin/perl -lw
use overload 'nomethod' => sub { return 0 };
print bless([], 'main') eq "oenthueonthu";

This program prints nothing, though it should print 1​:
#!/usr/bin/perl -lw
use overload 'nomethod' => sub { return 1 };
print bless([], 'main') eq "oenthueonthu";

And this program

#!/usr/bin/perl -lw
use overload 'nomethod' => sub { return 'something' };
print bless([], 'main') eq "oenthueonthu";

prints​:
Argument "something" isn't numeric in string eq at - line 3.
1

This happens because when a method for "eq" can't be found, perl looks
for a "cmp" method to fall back to. When it doesn't find one, it calls
the "nomethod" method and treats its return value as what you would
expect to get from "cmp". So "0" means "equal", "1" means "greater
than" and "something" evaluated as a number is 0, so it means "equal"
with a numeric warning.

What should happen when the "cmp" method is not found is that the
expectation of the return value should revert to that of the specified
method​: "eq" in this case.

Patch attached.

--
Rick Delaney
rick@​bort.ca

@p5pRT
Copy link
Author

p5pRT commented Feb 21, 2007

From rick@bort.ca

41546.patch
diff -pruN perl-current/gv.c perl-current-dev/gv.c
--- perl-current/gv.c	2007-02-18 14:41:07.000000000 -0500
+++ perl-current-dev/gv.c	2007-02-21 15:43:40.000000000 -0500
@@ -1871,6 +1871,19 @@ Perl_amagic_call(pTHX_ SV *left, SV *rig
     } else {
     not_found:			/* No method found, either report or croak */
       switch (method) {
+	 case lt_amg:
+	 case le_amg:
+	 case gt_amg:
+	 case ge_amg:
+	 case eq_amg:
+	 case ne_amg:
+	 case slt_amg:
+	 case sle_amg:
+	 case sgt_amg:
+	 case sge_amg:
+	 case seq_amg:
+	 case sne_amg:
+	   postpr = 0; break;
 	 case to_sv_amg:
 	 case to_av_amg:
 	 case to_hv_amg:
diff -pruN perl-current/lib/overload.t perl-current-dev/lib/overload.t
--- perl-current/lib/overload.t	2006-11-24 10:08:50.000000000 -0500
+++ perl-current-dev/lib/overload.t	2007-02-21 16:39:06.000000000 -0500
@@ -47,7 +47,7 @@ sub numify { 0 + "${$_[0]}" }	# Not need
 package main;
 
 $| = 1;
-use Test::More tests => 512;
+use Test::More tests => 522;
 
 
 $a = new Oscalar "087";
@@ -1286,3 +1286,50 @@ foreach my $op (qw(<=> == != < <= > >=))
     $c |= $d;
     is($c->val, 'c | d', "overloaded |= (by fallback) works");
 }
+
+{
+    # comparison operators with nomethod
+    my $warning = "";
+    my $method;
+
+    package nomethod_false;
+    use overload nomethod => sub { $method = 'nomethod'; 0 };
+
+    package nomethod_true;
+    use overload nomethod => sub { $method= 'nomethod'; 'true' };
+
+    package main;
+    local $^W = 1;
+    local $SIG{__WARN__} = sub { $warning = $_[0] };
+
+    my $f = bless [], 'nomethod_false';
+    ($warning, $method) = ("", "");
+    is($f eq 'whatever', 0, 'nomethod makes eq return 0');
+    is($method, 'nomethod');
+
+    my $t = bless [], 'nomethod_true';
+    ($warning, $method) = ("", "");
+    is($t eq 'whatever', 'true', 'nomethod makes eq return "true"');
+    is($method, 'nomethod');
+    is($warning, "", 'nomethod eq need not return number');
+
+    eval q{ 
+        package nomethod_false;
+        use overload cmp => sub { $method = 'cmp'; 0 };
+    };
+    $f = bless [], 'nomethod_false';
+    ($warning, $method) = ("", "");
+    ok($f eq 'whatever', 'eq falls back to cmp (nomethod not called)');
+    is($method, 'cmp');
+
+    eval q{
+        package nomethod_true;
+        use overload cmp => sub { $method = 'cmp'; 'true' };
+    };
+    $t = bless [], 'nomethod_true';
+    ($warning, $method) = ("", "");
+    ok($t eq 'whatever', 'eq falls back to cmp (nomethod not called)');
+    is($method, 'cmp');
+    like($warning, qr/isn't numeric/, 'cmp should return number');
+
+}

@p5pRT
Copy link
Author

p5pRT commented Feb 21, 2007

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

@p5pRT
Copy link
Author

p5pRT commented Feb 23, 2007

@rgs - Status changed from 'open' to 'resolved'

@p5pRT p5pRT closed this as completed Feb 23, 2007
@p5pRT
Copy link
Author

p5pRT commented Feb 23, 2007

From @rgarcia

On 21/02/07, Rick Delaney <rick@​bort.ca> wrote​:

What should happen when the "cmp" method is not found is that the
expectation of the return value should revert to that of the specified
method​: "eq" in this case.

Patch attached.

Thanks, applied as change #30383.

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

1 participant