Here's the information I was able to track down on the @ISA issues we ran into
back in 2001. Turns out chromatic tracked down the resolution we've been
using ever since then. In 0.10, I found the @$isa = @$isa code (had to track
down those versions in e-mails Ned and I sent each other). In 0.11 it was
gone. And then I found the following messages:
======BEGIN MESSAGE======
From: chromatic
Date: Sat, 14 Jul 2001 12:34:24 -0600
Subject: More @ISA Fun
I couldn't believe that manipulating @ISA was broken in 5.005, so I put
together a series of tests. It points to something wrong with isa(). I get
the same results on 5.6.0.
The attached file puts together two dummy packages and an object. It goes
through a few different ways to manipulate the object's @ISA. That works for
the method dispatch, but it never seems to invalidate the cache isa() uses.
The output should be 6 instances of 'ok' for expected dispatch successes or
failures. I see isa() failures on ref_isa() and direct assignment.
Additionally, after all of the manipulations, there's a check to see if the
initial contents of @ISA are still in the isa() cache. Unfortunately, they
are, so it displays "Really bad caching!".
I'm curious to see your results.
-- c
#!/usr/bin/perl -w
use strict;
package Zot;
package Foo;
sub foo { }
package Bar;
# works even without declaring
use vars qw( @ISA );
@ISA = ( 'Zot' );
sub new {
bless({}, $_[0]);
}
sub bar {}
sub plain_isa {
shift;
@Bar::ISA = @_;
}
my $isa = \@Bar::ISA;
sub ref_isa {
shift;
@$isa = @_;
}
package main;
# set up object, attempt normal dispatch
my $bar = Bar->new();
$bar->bar();
# check isa() to start
print "ISA: (@Bar::ISA)\n";
print "ok\n\n" if $bar->isa('Zot');
# check inheritance, call should fail
print "ISA: (@Bar::ISA)\n";
eval { $bar -> foo() };
warn "isa() failed initially!\n" if $bar->isa('Foo');
print "ok\n\n" if ($@ =~ /^Can't locate object method "foo"/);
# add parent via ref to @ISA, call should succeed
$bar->ref_isa('Foo');
print "ISA: (@Bar::ISA)\n";
eval { $bar -> foo() };
warn "isa() failed after ref_isa()!\n" unless $bar->isa('Foo');
print "ok\n\n" unless $@;
# remove parent via direct assignment, call should fail
$bar->plain_isa();
print "ISA: (@Bar::ISA)\n";
eval { $bar -> foo() };
warn "isa() failed after plain_isa()!\n" if $bar->isa('Foo');
print "ok\n\n" if ($@ =~ /^Can't locate object method "foo"/);
# manipulate inheritance directoy
@Bar::ISA = qw( Foo );
print "ISA: (@Bar::ISA)\n";
eval { $bar -> foo() };
warn "isa() failed in direct!\n" unless $bar->isa('Foo');
print "ok\n\n" unless $@;
# manipulate via symref in another package
{
no strict 'refs';
@{ ref($bar) . '::ISA' } = ();
}
print "ISA: (@Bar::ISA)\n";
eval { $bar -> foo() };
warn "isa() failed!\n" if $bar->isa('Foo');
warn "Really bad caching!\n" if $bar->isa('Zot');
print "ok\n\n" if ($@ =~ /^Can't locate object method "foo"/);
=======END MESSAGE=======
======BEGIN MESSAGE======
From: Ned Konz
Subject: Re: More @ISA Fun
Date: Sat, 14 Jul 2001 12:46:27 -0700
On Saturday 14 July 2001 11:34 am, you wrote:
Show quoted text> I couldn't believe that manipulating @ISA was broken in 5.005, so I put
> together a series of tests. It points to something wrong with isa(). I
> get the same results on 5.6.0.
Except that it works under 5.6.1 just fine. Ugh. I just installed 5.005 to
test with. Of course, both Toby and I have been testing (mostly) under 5.6.1.
Show quoted text> The attached file puts together two dummy packages and an object. It goes
> through a few different ways to manipulate the object's @ISA. That works
> for the method dispatch, but it never seems to invalidate the cache isa()
> uses.
>
> The output should be 6 instances of 'ok' for expected dispatch successes or
> failures. I see isa() failures on ref_isa() and direct assignment.
>
> Additionally, after all of the manipulations, there's a check to see if the
> initial contents of @ISA are still in the isa() cache. Unfortunately, they
> are, so it displays "Really bad caching!".
>
> I'm curious to see your results.
Under 5.005_03:
ISA: (Zot)
ok
ISA: (Zot)
ok
ISA: (Foo)
isa() failed after ref_isa()!
ok
ISA: ()
ok
ISA: (Foo)
isa() failed in direct!
ok
ISA: ()
Really bad caching!
ok
Under 5.6.1:
ISA: (Zot)
ok
ISA: (Zot)
ok
ISA: (Foo)
ok
ISA: ()
ok
ISA: (Foo)
ok
ISA: ()
ok
--
Ned Konz
=======END MESSAGE=======
======BEGIN MESSAGE======
From: chromatic
Date: Sat, 14 Jul 2001 14:11:44 -0600
Subject: Re: More @ISA Fun
On Saturday 14 July 2001 13:46, you wrote:
Show quoted text> > I couldn't believe that manipulating @ISA was broken in 5.005, so I put
> > together a series of tests. It points to something wrong with isa(). I
> > get the same results on 5.6.0.
>
> Except that it works under 5.6.1 just fine. Ugh. I just installed 5.005 to
> test with. Of course, both Toby and I have been testing (mostly) under
> 5.6.1.
Yes, this seems to have come up on p5p last year.
http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2000-03/msg02705.html
Borrowing from a fix by Nick Ing-Simmons, I've created another patch that
fixes that particular nastiness.
My test and t/include.t now both run correctly.
-- c
=======END MESSAGE=======
And, cropping the patch down to some example lines:
======BEGIN PATCH SEGMENT======
@@ -779,7 +793,11 @@
my $splice_point = $parent_header ? 0 :
@$parentOrder;
splice( @$isa, $splice_point, 0, $parentPackage );
- @$isa = @$isa; #Defends against ISA caching problems
+ {
+ #Defends against ISA caching problems
+ no strict 'refs';
+ delete ${"$package\::"}{'::ISA::CACHE::'};
+ }
splice( @$parentOrder, $splice_point, 0, $slot );
}
else {
=======END PATCH SEGMENT=======
So, on July 14, 2001, we changed our workaround for the ISA caching problems
from using @$isa = @$isa to deleting ::ISA::CACHE:: from the namespace.
Which worked for 5.005 through 5.8. Should I return to @$isa = @$isa? Or is
there a new approved mechanism for resetting the ISA cache?
--Toby Ovod-Everett