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

Creating accessor method using SUPER name stopped to work #13783

Open
p5pRT opened this issue Apr 29, 2014 · 8 comments
Open

Creating accessor method using SUPER name stopped to work #13783

p5pRT opened this issue Apr 29, 2014 · 8 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 29, 2014

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

Searchable as RT121766$

@p5pRT
Copy link
Author

p5pRT commented Apr 29, 2014

From migo@freeshell.org

The following test program demonstrates a regression in perl 5.18​:

  @​Class2​::ISA = qw(Class1);
  sub Class1​::AUTOLOAD {
  *{$Class1​::AUTOLOAD} = sub { print "defined\n" };
  print "autoloaded\n";
  }

  Class2->Class2​::SUPER​::a;
  Class2->Class2​::SUPER​::a;
  Class2->a;
  Class2->a;

In perl versions prior to 5.18.0 it prints​:

  autoloaded
  defined
  autoloaded
  defined

In 5.18.0 (and 5.18.2) it prints "autoloaded" 3 times in a row.
And Class2->can('Class2​::SUPER​::a') returns undef instead of CODE,
although the method gets re-defined every time, causing warnings
"Subroutine SubClass​::SUPER​::method redefined" in my real code.

Best regards,

Mikhael

@p5pRT
Copy link
Author

p5pRT commented Apr 30, 2014

From @tonycoz

On Tue Apr 29 15​:13​:01 2014, migo@​freeshell.org wrote​:

The following test program demonstrates a regression in perl 5.18​:

@​Class2​::ISA = qw\(Class1\);
sub Class1​::AUTOLOAD \{
    \*\{$Class1​::AUTOLOAD\} = sub \{ print "defined\\n" \};
    print "autoloaded\\n";
\}

Class2\->Class2​::SUPER​::a;
Class2\->Class2​::SUPER​::a;
Class2\->a;
Class2\->a;

In perl versions prior to 5.18.0 it prints​:

autoloaded
defined
autoloaded
defined

In 5.18.0 (and 5.18.2) it prints "autoloaded" 3 times in a row.
And Class2->can('Class2​::SUPER​::a') returns undef instead of CODE,
although the method gets re-defined every time, causing warnings
"Subroutine SubClass​::SUPER​::method redefined" in my real code.

Bisected to​:

aae4380 is the first bad commit
commit aae4380
Author​: Father Chrysostomos <sprout@​cpan.org>
Date​: Mon Sep 17 16​:24​:40 2012 -0700

  [perl #114924] Make method calls work with :​:SUPER packages
 
  Perl caches SUPER methods inside packages named Foo​::SUPER. But this
  interferes with actual method calls on those packages (SUPER->foo,
  foo​::SUPER->foo).
 
  The first time a package is looked up, it is vivified under the name
  with which it is looked up. So *SUPER​:: will cause that package
  to be called SUPER, and *main​::SUPER​:: will cause it to be named
  main​::SUPER.
 
  main->SUPER​::isa used to be very sensitive to the name of the
  main​::FOO package (where the cache is kept). If it happened to be
  called SUPER, that call would fail.
  ...
 
Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 30, 2014

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

@p5pRT
Copy link
Author

p5pRT commented Jul 13, 2014

From @rjbs

This seems like a 5.22.0 blocker, and something we'd want to backport when fixed.

Agreed?

@p5pRT
Copy link
Author

p5pRT commented Jul 15, 2014

From @tonycoz

On Sun Jul 13 11​:27​:34 2014, rjbs wrote​:

This seems like a 5.22.0 blocker, and something we'd want to backport
when fixed.

I'm not sure it's fixable without reverting the patch that changed the behaviour.

Both before and after the patch, $Class2​::AUTOLOAD is set to "Class2​::SUPER​::a" for the SUPER call​:

  # system perl is 5.14.2
  tony@​mars​:.../git/perl2$ perl ../super-autoload.pl
  autoloaded Class2​::SUPER​::a
  defined
  autoloaded Class2​::a
  defined

  tony@​mars​:.../git/perl2$ ~/perl/5.20.0-dbg/bin/perl ../super-autoload.pl
  autoloaded Class2​::SUPER​::a
  autoloaded Class2​::SUPER​::a
  autoloaded Class2​::a
  defined

Before the patch, perl used *{"${package}​::SUPER"} as a cache for SUPER lookups, so the assignment to *{$Class1​::AUTOLOAD} updated the cache directly. The next call to SUPER​::a finds the entry in the cache and everything (sort of) works.

After the patch, perl no longer looks in *{"${package}​::SUPER"}, so the second call doesn't find the entry the first call added.

One solution might be to not paste "SUPER​::" into $AUTOLOAD​:

--- a/gv.c
+++ b/gv.c
@​@​ -1116,7 +1116,6 @​@​ Perl_gv_autoload_pvn(pTHX_ HV *stash, const char *name, ST
  }
  else
  packname = sv_2mortal(newSVhek(HvNAME_HEK(stash)));
- if (flags & GV_SUPER) sv_catpvs(packname, "​::SUPER");
  }
  if (!(gv = gv_fetchmeth_pvn(stash, S_autoload, S_autolen, FALSE,
  is_utf8 | (flags & GV_SUPER))))

but this doesn't restore the old behaviour​:

  tony@​mars​:.../git/perl2$ ./perl ../super-autoload.pl
  autoloaded Class2​::a
  autoloaded Class2​::a
  defined
  defined

It removes the ability to distinguish between SUPER and non-SUPER calls (if that's useful at all.)

Tony

@p5pRT
Copy link
Author

p5pRT commented Jul 16, 2014

From @rjbs

* Tony Cook via RT <perlbug-followup@​perl.org> [2014-07-14T21​:33​:11]

Both before and after the patch, $Class2​::AUTOLOAD is set to
"Class2​::SUPER​::a" for the SUPER call​:
[...]

Thanks, that's all useful information that I will have to digest.

What a mess. :( SUPER!

Anybody else want to throw opinions in here?

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Jul 16, 2014

From @ikegami

On Mon, Jul 14, 2014 at 9​:33 PM, Tony Cook via RT <perlbug-followup@​perl.org

wrote​:

One solution might be to not paste "SUPER​::" into $AUTOLOAD​:

[...]

but this doesn't restore the old behaviour​:

tony@​mars​:.../git/perl2$ ./perl ../super-autoload.pl
autoloaded Class2​::a
autoloaded Class2​::a
defined
defined

You're calling Class1​::a, not calling Class2​::a. That seems worse.

@p5pRT
Copy link
Author

p5pRT commented Nov 9, 2015

From @rjbs

I don't have any solution to offer to restore the old behavior without reintroducing old problems.

What would we want out of a solution to this moving forward? If we want to install the method that was autoloaded, there are two likely candidates for where to install it​:

1) the package where the called AUTOLOAD was called
2) the package where we first looked for the method

The first can be done, generally, by having AUTOLOAD use __PACKAGE___.

The second is more of a problem, here, because of the inherent ambiguity between SUPER and SUPER. We could provide (say) *AUTOLOAD to which a subroutine to be installed at the original call site could be assigned. We could provide a means to get the resolved package we're trying to look in (ParentClass instead of ChildClass​::SUPER for when AUTOLOAD is in GrandParentClass). It is unfortunate that this changed without our noticing or issuing a notice, but I'm not eager to vacillate between two buggy states if we can provide better.

--
rjbs

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

No branches or pull requests

2 participants