Почему Try::Tiny "try {}" отличается от "eval {}" для объектов, созданных внутри блока try?

У меня есть следующий код инициализации в системном трее апплета:

use Gtk3 -init;
use Glib::Object::Introspection;

eval {
    Glib::Object::Introspection->setup(
        basename => 'Notify',
        version => '0.7',
        package => "MyProgram::Notify",
        );
};

if ($@) {
    say "no notify because setup failed: $@";
    $use_notify = 0;
} else {
    MyProgram::Notify->init();
}

Этот код основан на fdpowermon, но, похоже, более или менее взят из примеров обработки исключений в POD Glib:: Object:: Introspection.

Но perlcritic (на уровне 3) спорит об этом:

Return value of eval not tested at line …

Поэтому я попытался переписать это с помощью Try:: Tiny:

use Gtk3 -init;
use Glib::Object::Introspection;
use Try::Tiny;

try {
    Glib::Object::Introspection->setup(
        basename => 'Notify',
        version => '0.7',
        package => "MyProgram::Notify",
        );
} catch {
    say "no notify because setup failed: $@";
    $use_notify = 0;
} finally {
    if (!$@) {
        MyProgram::Notify->init();
    }
}

Но тогда Perl утверждает:

Can't locate object method "new" via package MyProgram::Notify::Notification

Хотя я вижу, что особенно finally блок не является реальным улучшением, я не понимаю, почему использование Try:: Tiny имеет такое значение в отношении пакета, созданного Glib::Object::Introspection.

Или есть лучший способ, чем Try:: Tiny, чтобы сделать этот код более элегантным и читаемым, сохраняя при этом perlcritic счастливый?

2 ответа

Весь смысл критики состоит в том, чтобы избежать проверки $@ потому что это могло быть забито. Но после всех ваших изменений вы все еще проверяете $@!

Хуже, попробуйте:: Tiny помещает ошибку в $_, не в $@и только в catch блоки.

Я думаю, что происходит то, что MyProgram::Notify->init() вызывается, когда не следует из-за вышеперечисленных ошибок.

Fix:

my $use_notify = 1;
try {
    Glib::Object::Introspection->setup(
        basename => 'Notify',
        version => '0.7',
        package => "MyProgram::Notify",
    );

    MyProgram::Notify->init();
} catch {
    say "no notify because setup failed: $_";
    $use_notify = 0;
}

или же

my $use_notify = 1;
try {
    Glib::Object::Introspection->setup(
        basename => 'Notify',
        version => '0.7',
        package => "MyProgram::Notify",
    );
} catch {
    say "no notify because setup failed: $_";
    $use_notify = 0;
}

MyProgram::Notify->init() if $use_notify;

Без попытки:: Tiny:

my $use_notify = 1;
if (!eval {
    Glib::Object::Introspection->setup(
        basename => 'Notify',
        version => '0.7',
        package => "MyProgram::Notify",
    );

    MyProgram::Notify->init();

    1;  # No exception
}) {
    say "no notify because setup failed: " . ( $@ // "Unknown error" );
    $use_notify = 0;
}

или же

my $use_notify = 1;
if (!eval {
    Glib::Object::Introspection->setup(
        basename => 'Notify',
        version => '0.7',
        package => "MyProgram::Notify",
    );
    1;  # No exception
}) {
    say "no notify because setup failed: " . ( $@ // "Unknown error" );
    $use_notify = 0;
}

MyProgram::Notify->init() if $use_notify;

На самом деле ответ на мой вопрос в основном такой же: пропущенная точка с запятой за catch (или скорее finally) блок.

Извините за шум.

Другие вопросы по тегам