среда, 1 декабря 2010 г.

Чем плох eval?!

Чем плох eval?!
В perl, как всем известно, имеется 2 варианта вызова функции eval. Строковый eval для компиляции и выполнения кода на лету и блочный eval.
Нас интересует блочный eval.
Часто встречается такой вот код:


eval { 
  # some code 
  die "error"; 
  # some code  
}; 

if ($@) { 
    print "Error [$@] occured!"; 
}

Это вполне стандартный код, но есть ряд недостатков связанных и с использованием глобальной переменной $@.
Потенциальная проблема #1
Если кто-то локализировал переменную $@, то мы не сможем перехватить исключение. В этом коде мы не видим ошибки.


sub do_die { 
    die "Error"; 
} 

eval { 
    local $@;
    do_die(); 
}; 

if ($@) { 
    print "Error [$@] Occured!"; 
} 


Потенциальная проблема #2
Если в деструкторе используется eval, то скорее всего мы не перехватим исключение. Пример:

package Object;
sub new { 
    my $class = shift; 
    my $self  = {}; 
    bless $self, $class; 
}

sub DESTROY {
    eval { 
        # some clean code 
    } 
} 

package main; 
eval { 
    my $obj = Object->new(); 
    die  "Error"; 
}; 

if ($@) { 
    print "Error [$@] Occured!";
} 

  Деструктор с eval-ом может быть в ком-то модуле с CPANа и Вы просто не будете знать про это.
Потенциальная проблема #3
 $@ может содержать объект, которые в булевом контексте вернет ложь.

Решение
В связи со всем вышесказанным, рекомендую использовать  модуль Try::Tiny либо TryCatch. Они позволят Вам  избежать описанных проблем в будущем  и предоставят удобные и понятные синтаксический конструкции(try{}catch{} finally{}).  

Я использую Try::Tiny, он мне нравится своей минималистичностью и отсутствием внешних зависимостей. 

Вот пример кода с Try::Tiny. Красиво и надежно :).
# handle errors with a catch handler
try {
    die "foo";
}
catch {
    warn "caught error: $_";    # not $@
};

# just silence errors
try {
    die "foo";
};
Более доходчиво про это все написано в "perldoc Try::Tiny".

1 коммент.:

Анонимный комментирует...

TryCatch как-то проблемно устанавливается в последнее время (не проходит часть тестов под windows), потому тоже пользуюсь Try::Tiny, что и остальным желаю.

Отправить комментарий

Не забудьте добавить себя в постоянные читатели и включить уведомления о новых комментариях, либо воспользуйтесь RSS каналом ;)