Есть ли проблема в Perl 5.12.2 при использовании сплайсинга на @ISA? - PullRequest
11 голосов
/ 15 октября 2010

Ниже приведен сеанс отладки в 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?

Ответы [ 2 ]

14 голосов
/ 15 октября 2010

Замена для Class::ISA::self_and_super_path - mro::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 или присвоение, или, возможно, попытаться mro::method_changed_in, что сделает недействительными кэши разрешения методов, которые связаны с различными @ISA s. 1023 *

Если бы вы могли уменьшить эту ошибку до минимального теста, это было бы чрезвычайно полезно для исправления этой ошибки.

Обновление:

Минимальный тестовый случай оказался простым:

$ 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, следующей северной весной, вероятно, будут иметь его.

4 голосов
/ 15 октября 2010

Да, есть кеш. Но если вы можете изменить @ISA без аннулирования этого кэша, я бы посчитал это ошибкой в ​​perl.

Ваша проблема исчезнет, ​​если вы добавите строку @ISA = @ISA; после строки splice?

...