2013-02-04 2 views
2

Итак, в эти дни я работаю с проектом, который использует Perl и Moose. Я понимаю, что Муз построен на СС. Я не слишком хорошо знаком с СС, и я столкнулся с чем-то, чего не понимаю, и я мог бы использовать теоретическое объяснение. Вот это модуль namespace::autoclean «в документации:Объясните это колдовство !!! (в Perl, с Moose и namespace :: autoclean)

SYNOPSIS 
    package Foo; 
    use namespace::autoclean; 
    use Some::Package qw/imported_function/; 

    sub bar { imported_function('stuff') } 

    # later on: 
    Foo->bar;    # works 
    Foo->imported_function; # will fail. imported_function got cleaned after compilation 

Так, назад, прежде чем я когда-либо использовали лось, так, что вы называемый метод на объекте был: интерпретатор Perl будет выглядеть на этот метод в таблице символов пакет, на который был благословлен ваш объект (тогда, если не найден, рассмотрите наследование и т. п.). То, как оно называлось импортированной функцией внутри пакета, было: оно искало имя функции в таблице символов пакета. Насколько мне известно до настоящего времени, это означает одну и ту же таблицу символов, так что это поведение должно быть невозможно.

Мой первоначальный осмотр источника не был продуктивным. В широком смысле, что отличает при использовании Moose, MOP и namespace :: autoclean, что этот вид обмана становится возможным?

ed. Чтобы быть особенно понятно, если бы я был заменить use namespace::autoclean с

CHECK { undef *Foo::imported_function } 

то Foo->bar; вызова описан в документации будет врезаться, потому что Foo->bar не знает, где найти imported_function.

+0

Просто на длинном снимке: может быть, с помощью 'use subs qw/imported_функции /;' остановить автоочистку? Или импортировать * перед * загрузкой 'namespace :: autoclean'? – amon

ответ

3

Это на самом деле довольно просто. Для

some_sub() 

some_sub разрешен при компиляции. Для

$o->some_method() 

some_method разрешен во время выполнения. Это невозможно сделать во время компиляции, поскольку оно зависит от значения $o.

+1

Ах. И если я сделал 'sub bar {no strict 'refs'; my $ func = "imported_функция"; & $ func ('stuff')} 'it * не будет * работать. – fennec

1

Здесь нет ничего нестандартного. Линейные

use Some::Package qw/imported_function/; 

импорт imported_function в текущий пакет, так Foo::imported_function такая же, как подпрограмма Some::Package::imported_function. Это предполагает, что Some::Package наследует от Exporter, чтобы выполнить необходимые манипуляции с таблицами символов.

Звонки - это вызовы методов, поэтому Foo->bar - это то же самое, что и Foo::bar('Foo'). Единственная особенность здесь в том, что магия, которая была выполнена функцией import от Exporter, отменена в конце времени компиляции на namespace::autoclean.

Я не смотрел на код этого модуля, но так как таблица символов из пакета только хэш (известный как тайник для символов хэш-таблицы) было бы легко сохранить свое состояние в один пункт и восстановить его впоследствии. Поэтому я бы предположил, что namespace::autoclean принимает снимок таблицы символов, когда он загружен, и восстанавливает состояние, указанное в конце времени компиляции. Это удобно сделать в CHECK block, который ведет себя как блок BEGIN, но выполняется в конце компиляции и перед запуском запуска.

+0

«Итак, я бы предположил, что пространство имен :: autoclean принимает моментальный снимок таблицы символов при его загрузке и восстанавливает состояние, указанное в конце времени компиляции». Компиляция времени в таблице символов * является простой, но разрешение импортированного метода вызывает 'sub bar {imported_функция ('stuff')}', что происходит, когда вы вызываете 'Foo-> bar' ... ** во время выполнения **. Например, вы заметите, что это не работает: https://gist.github.com/4708620 Очевидно, что это не полное объяснение механизма, который работает. – fennec

+0

@fennec Конечно. Тем не менее, вы 'undef' сделали сам sub, вместо того, чтобы удалять только имя из stash →' delete $ {Foo ::} {pseudoimport} ', и он работает. (для многих имен: 'delete @ {Foo ::} {@ list_of_names};'). Конечно, такое варварство уничтожает * любую * переменную с тем же именем). – amon

+0

Хорошо, это интересно. Так где же код для Foo :: pseudoimport жить после 'delete $ {Foo ::} {псевдоимпорт}'? – fennec

Смежные вопросы