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

UNIVERSAL::can is wrong for unloaded classes #9098

Closed
p5pRT opened this issue Nov 2, 2007 · 11 comments
Closed

UNIVERSAL::can is wrong for unloaded classes #9098

p5pRT opened this issue Nov 2, 2007 · 11 comments

Comments

@p5pRT
Copy link

p5pRT commented Nov 2, 2007

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

Searchable as RT47113$

@p5pRT
Copy link
Author

p5pRT commented Nov 2, 2007

From @btilly

Created by btilly@gmail.com

  unless (Foo->can("can")) {
  print "can tells me that it can't be called!"
  }

As the code snippet above demonstrates, if the package Foo is
not yet in the symbol table, you can call the can method on it,
but can will incorrectly not see that UNIVERSAL methods can
be called on Foo.

In case anyone wonders whether the ability to call can is a
special case, I already tested that.

  sub UNIVERSAL​::bar {
  print "bar was called\n";
  }

  Foo->bar(); # Prints
  print Foo->can("bar"); # Doesn't find the method

After the line "package Foo;" has been read, though, can will
work correctly.

This behaviour came up in
http​://use.perl.org/comments.pl?sid=37415. It leads to this
incorrect warning from the core module UNIVERSAL​::can​:

  use warnings;
  use UNIVERSAL​::can;

  # This warns that we're calling can as a function.
  # But we aren't!
  unless (Foo->can("new")) {
  print "Foo is not loaded\n";
  }

I've also submitted a patch to chromatic that would get rid of
this incorrect warning. But his code was logically correct, and
would not have warned were it not for the core Perl bug.

Cheers,
Ben

Perl Info

Flags:
    category=core
    severity=low

This perlbug was built using Perl v5.8.6 in the Red Hat build system.
It is being executed now by Perl v5.8.6 - Wed May 18 18:20:12 EDT 2005.

Site configuration information for perl v5.8.6:

Configured by Red Hat, Inc. at Wed May 18 18:20:12 EDT 2005.

Summary of my perl5 (revision 5 version 8 subversion 6) configuration:
  Platform:
    osname=linux, osvers=2.4.21-27.0.2.elsmp, archname=i386-linux-thread-multi
    uname='linux decompose.build.redhat.com 2.4.21-27.0.2.elsmp #1 smp wed jan 12 23:35:44 est 2005 i686 i686 i386 gnulinux '
    config_args='-des -Doptimize=-O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -Dversion=5.8.6 -Dmyhostname=localhost -Dperladmin=root@localhost -Dcc=gcc -Dcf_by=Red Hat, Inc. -Dinstallprefix=/usr -Dprefix=/usr -Darchname=i386-linux -Dvendorprefix=/usr -Dsiteprefix=/usr -Duseshrplib -Dusethreads -Duseithreads -Duselargefiles -Dd_dosuid -Dd_semctl_semun -Di_db -Ui_ndbm -Di_gdbm -Di_shadow -Di_syslog -Dman3ext=3pm -Duseperlio -Dinstallusrbinperl=n -Ubincompat5005 -Uversiononly -Dpager=/usr/bin/less -isr -Dd_gethostent_r_proto -Ud_endhostent_r_proto -Ud_endprotoent_r_proto -Ud_endservent_r_proto -Ud_sethostent_r_proto -Ud_setprotoent_r_proto -Ud_setservent_r_proto -Dinc_version_list=5.8.5 5.8.4 5.8.3'
    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='gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DDEBUGGING -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm',
    optimize='-O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DDEBUGGING -fno-strict-aliasing -pipe -I/usr/local/include -I/usr/include/gdbm'
    ccversion='', gccversion='4.0.0 20050516 (Red Hat 4.0.0-6)', 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='gcc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lresolv -lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lpthread -lc
    perllibs=-lresolv -lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
    libc=/lib/libc-2.3.5.so, so=so, useshrplib=true, libperl=libperl.so
    gnulibc_version='2.3.5'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E -Wl,-rpath,/usr/lib/perl5/5.8.6/i386-linux-thread-multi/CORE'
    cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:
    


@INC for perl v5.8.6:
    /usr/lib/perl5/site_perl/5.8.6/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.5/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.4/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.3/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.6
    /usr/lib/perl5/site_perl/5.8.5
    /usr/lib/perl5/site_perl/5.8.4
    /usr/lib/perl5/site_perl/5.8.3
    /usr/lib/perl5/site_perl
    /usr/lib/perl5/vendor_perl/5.8.6/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.5/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.4/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.3/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.6
    /usr/lib/perl5/vendor_perl/5.8.5
    /usr/lib/perl5/vendor_perl/5.8.4
    /usr/lib/perl5/vendor_perl/5.8.3
    /usr/lib/perl5/vendor_perl
    /usr/lib/perl5/5.8.6/i386-linux-thread-multi
    /usr/lib/perl5/5.8.6
    .


Environment for perl v5.8.6:
    HOME=/users/btilly
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/usr/kerberos/bin:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/usr/games:/opt/ant/bin:/opt/tomcat/bin:/opt/java/bin:/users/btilly/bin:/opt/java/bin:/opt/java/bin:/opt/java/bin
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Jun 22, 2012

From @doy

I've pushed a fix for this to the doy/universal branch. It's pretty
straightforward, but some of the tests in t/op/universal.t were testing
for this behavior explicitly (checking that can() was false before a
package existed and true afterwards), so I'm not sure if this is
reasonable to just change directly. I am in favor of making this change
though, so any input is welcome.

@p5pRT
Copy link
Author

p5pRT commented Jun 22, 2012

From [Unknown Contact. See original ticket]

I've pushed a fix for this to the doy/universal branch. It's pretty
straightforward, but some of the tests in t/op/universal.t were testing
for this behavior explicitly (checking that can() was false before a
package existed and true afterwards), so I'm not sure if this is
reasonable to just change directly. I am in favor of making this change
though, so any input is welcome.

@p5pRT
Copy link
Author

p5pRT commented Jun 22, 2012

@doy - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jun 22, 2012

From @cpansprout

On Fri Jun 22 12​:14​:55 2012, doy wrote​:

I've pushed a fix for this to the doy/universal branch. It's pretty
straightforward, but some of the tests in t/op/universal.t were testing
for this behavior explicitly (checking that can() was false before a
package existed and true afterwards), so I'm not sure if this is
reasonable to just change directly. I am in favor of making this change
though, so any input is welcome.

I think $class->can('can') is a fairly popular way to see whether a
class is loaded.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jun 22, 2012

From @doy

On Fri, Jun 22, 2012 at 12​:35​:32PM -0700, Father Chrysostomos via RT wrote​:

On Fri Jun 22 12​:14​:55 2012, doy wrote​:

I've pushed a fix for this to the doy/universal branch. It's pretty
straightforward, but some of the tests in t/op/universal.t were testing
for this behavior explicitly (checking that can() was false before a
package existed and true afterwards), so I'm not sure if this is
reasonable to just change directly. I am in favor of making this change
though, so any input is welcome.

I think $class->can('can') is a fairly popular way to see whether a
class is loaded.

But (as mst pointed out on #p5p) it doesn't do that at all​:

$ perl -E'package Foo​::Bar; say Foo->can("can")'
CODE(0x1f4a220)

(since namespaces nest). And having $foo->can("can") not die and yet not
return anything really seems nonsensical. This feels analogous to the
defined(@​array) issue, to me - people may be using it, but it really
doesn't do what they think it does, and using it in this way can cause a
lot of subtle bugs.

-doy

@p5pRT
Copy link
Author

p5pRT commented Jun 22, 2012

From @cpansprout

On Fri Jun 22 12​:50​:38 2012, doy@​tozt.net wrote​:

On Fri, Jun 22, 2012 at 12​:35​:32PM -0700, Father Chrysostomos via RT
wrote​:

On Fri Jun 22 12​:14​:55 2012, doy wrote​:

I've pushed a fix for this to the doy/universal branch. It's pretty
straightforward, but some of the tests in t/op/universal.t were
testing
for this behavior explicitly (checking that can() was false before a
package existed and true afterwards), so I'm not sure if this is
reasonable to just change directly. I am in favor of making this
change
though, so any input is welcome.

I think $class->can('can') is a fairly popular way to see whether a
class is loaded.

But (as mst pointed out on #p5p) it doesn't do that at all​:

$ perl -E'package Foo​::Bar; say Foo->can("can")'
CODE(0x1f4a220)

(since namespaces nest). And having $foo->can("can") not die and yet not
return anything really seems nonsensical. This feels analogous to the
defined(@​array) issue, to me - people may be using it, but it really
doesn't do what they think it does, and using it in this way can cause a
lot of subtle bugs.

Fairy nuff. :-)

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jun 22, 2012

From @rjbs

* Jesse Luehrs via RT <perlbug-comment@​perl.org> [2012-06-22T15​:14​:56]

I am in favor of making this change though, so any input is welcome.

It seems to bring ->can closer to reflecting reality, which sounds good.

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Jun 23, 2012

From @doy

Fixed by 68b4061.

@p5pRT
Copy link
Author

p5pRT commented Jun 23, 2012

From [Unknown Contact. See original ticket]

Fixed by 68b4061.

@p5pRT
Copy link
Author

p5pRT commented Jun 23, 2012

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

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