Есть ли проблема в perl 5.12.2 с использованием сплайсинга на @ISA?

Ниже представлен отладочный сеанс на Perl 5.12. Есть ли в этом смысл? UNIVERSAL кэширует версию переменной @ISA, которая, если навсегда ее использует. Назад до Class::ISA устарел, я использовал для вызова Class::ISA::self_and_super_path, чтобы заставить внутренние элементы relook в массиве @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?

Ответ 1

Замена 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.

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

Update:

Минимальный тестовый тест оказался легким:

$ 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, следующий северный spring, вероятно, получит его.

Ответ 2

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

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