Почему `$ @` недостоверно?

Кажется, я помню, что безопасно доверять значение [email protected] после eval. Что-то о обработчике сигнала, имеющем шанс установить [email protected], прежде чем вы его увидите или что-то в этом роде. Я тоже слишком устал и ленив сейчас, чтобы отследить реальную причину. Итак, почему небезопасно доверять [email protected]?

Ответы

Ответ 1

Try::Tiny perldoc имеет окончательное обсуждение проблемы с [email protected]:

Существует ряд проблем с eval.

Clobbering [email protected]

Когда вы запустите блок eval и он преуспеет, [email protected]будет очищен, что потенциально сбивает ошибку, которая в настоящее время улавливается.

Это вызывает действие на расстоянии, очищая предыдущие ошибки, которые ваш вызывающий абонент еще не обработал.

[email protected]должен быть правильно локализован перед вызовом eval, чтобы избежать этой проблемы.

Более конкретно, [email protected]сбивается в начале eval, что также делает невозможным захват предыдущей ошибки перед тем, как вы умрете (например, при создании объектов исключений со стеками ошибок).

По этой причине try фактически установит [email protected]на свое предыдущее значение (до локализации) в начале блока eval.

Локализация [email protected]молча маскирует ошибки

Внутри блока eval block ведет себя вроде:

sub die {
        [email protected] = $_[0];
        return_undef_from_eval();
}

Это означает, что если вы были вежливым и локализованным [email protected], вы не можете умереть в этой области или ваша ошибка будет отброшена (вместо этого напечатайте "Что-то не так" ).

Обходной путь очень уродлив:

my $error = do {
        local [email protected];
        eval { ... };
        [email protected];
};

...
die $error;

[email protected]может не быть истинным значением

Этот код неверен:

if ( [email protected] ) {
        ...
}

потому что из-за предыдущих предостережений он может быть отменен.

[email protected]также может быть перегруженным объектом ошибки, который оценивает значение false, но это все равно вызывает проблемы.

Классический режим отказа:

sub Object::DESTROY {
        eval { ... }
}

eval {
        my $obj = Object->new;

        die "foo";
};

if ( [email protected] ) {

}

В этом случае, поскольку Object:: DESTROY не локализует [email protected], но все еще использует eval, он установит [email protected]на ".

Деструктор вызывается, когда стек разматывается, после того как die устанавливает [email protected]на" foo на Foo.pm line 42\n", поэтому к моменту вычисления ($ @) он был очищен eval в деструктор.

Обходной путь для этого еще более уродливый, чем предыдущие. Несмотря на то, что мы не можем сохранить значение [email protected]из кода, который не локализуется, мы можем по крайней мере убедиться, что eval был прерван из-за ошибки:

my $failed = not eval {
        ...

        return 1;
};

Это потому, что eval, который поймал die, всегда будет возвращать ложное значение.

Ответ 3

[email protected] имеет те же проблемы, что и всякая глобальная переменная: когда что-то еще устанавливает, оно reset для всей программы. Любой eval может установить [email protected]. Даже если вы не видите рядом с eval, вы не знаете, кто еще может его назвать (подпрограммы, связанные переменные и т.д.).