11

以下是 Perl 5.12 上的调试会话。这有道理吗?是否UNIVERSAL缓存@ISA变量的版本,如果永远使用它。在不推荐使用之前Class::ISA,我曾经打电话Class::ISA::self_and_super_path让内部重新查看@ISA数组。既然现在认为它是不必要的,那么你如何让 perl 来审计它的内部记录呢?

DB<34> p $papa
Papushka=HASH(0x16bc0300)

DB<35> p $papa->isa('Nanushka')

DB<36> p $papa->isa('Babushka')
1

DB<37> x @Papushka::ISA
0  'Nanushka'
1  'Babushka'

这是测试代码(显然)。它得到相同的结果,运行平坦,作为测试运行,或在调试中运行。我应该告诉你,在此之前@ISA = qw<Babushka>,我表演过

splice( @ISA, 0, 0, 'Nanushka' );

那是问题吗?你应该只push进入@ISA吗?

4

2 回答 2

14

的替代品Class::ISA::self_and_super_pathmro::get_linear_isa。这可以从mro它本身获得,或者,如果你想支持旧的 perls,可以通过MRO::Compat.

此外,@ISA是一个神奇的变量。

$ perl -MDevel::Peek -e'Dump \@ISA'
SV = IV(0x1b92e20) at 0x1b92e28
  REFCNT = 1
  FLAGS = (TEMP,ROK)
  RV = 0x1bbcd58
  SV = PVAV(0x1b93cf8) at 0x1bbcd58
    REFCNT = 2
    FLAGS = (SMG,RMG)
    MAGIC = 0x1bc0f68
      MG_VIRTUAL = &PL_vtbl_isa
      MG_TYPE = PERL_MAGIC_isa(I)
      MG_OBJ = 0x1bbcd40
    ARRAY = 0x0
    FILL = -1
    MAX = -1
    ARYLEN = 0x0
    FLAGS = (REAL)

注意PERL_MAGIC_isa. 这就是驱动这种特殊机制的原因。

每当它被改变时,任何依赖于它的值的缓存的内容都应该被更新。

$ perl -E'say Foo->isa(q[Bar]) || 0; @Foo::ISA = qw(Bar Baz); say Foo->isa(q[Bar]) || 0'
0
1

显然,您发现了一个没有发生缓存失效的情况。我认为这是一个错误。出于splice某种原因,很可能没有isa适当地调用魔法。您可以尝试以@ISA另一种方式进行修改,例如使用unshift或 赋值,或者可能 try mro::method_changed_in,这将使绑定到各种@ISAs 的方法解析缓存无效。

如果您可以将此错误减少到最小的测试用例,那将对修复此错误非常有帮助。

更新:

一个最小的测试用例结果很简单:

$ perl -E'say Foo->isa(q[Bar]) || 0; splice @Foo::ISA, 0, 0, q[Bar]; say Foo->isa(q[Bar]) || 0'
0
0

这是由于pp_splice没有做类似的事情造成的mg_set((SV *)ary)push, unshift, 和常规分配可以正确执行此操作,因此使用其中之一应该可以解决您的问题。

另一个更新:

我刚刚提交给 perl 的这个更改解决了这个问题。然而,由于splice不调用魔法的奇怪行为已经出现在 5.8 和 5.10 中,它不是回归,因此在几个月内不会成为 5.12.3 的一部分。下周发布的5.13.6,明年北方春天的5.14.0,大概会有吧。

于 2010-10-15T16:41:53.873 回答
4

是的,有一个缓存。但是如果你可以@ISA在不使缓存失效的情况下进行修改,我会认为它是 perl 中的一个错误。

@ISA = @ISA;如果您在行后添加行,您的问题会消失splice吗?

于 2010-10-15T16:38:27.340 回答