Pregunta ¿Aún se recomienda Try :: Tiny para el manejo de excepciones en Perl 5.14 o posterior?


El consenso de la comunidad de Perl parece ser que Try::Tiny es la forma preferida de manejar excepciones.

Perl 5.14 (que es la versión que uso) parece resolver el cuestiones con eval ese Try::Tiny direcciones. Será Try::Tiny todavía me proporciona algún beneficio?


74
2018-04-28 15:34


origen


Respuestas:


Mi respuesta es impopular, pero no creo que los programadores de Perl intenten usar la noción extremadamente pobre de lo que llamamos "excepciones" en Perl. Estos son esencialmente un valor de retorno del canal lateral. Sin embargo, aún estando enamorado de la idea de excepciones, incluso con todas las complejidades de usar una variable global para pasar el estado, la gente sigue tratando de hacerlo funcionar.

Prácticamente, sin embargo, las personas usan die para señalar la falla. Algunos dirán que puedes die con una referencia y devuelve objetos de error, pero no necesita die para eso. Tenemos objetos, entonces debemos usar todo el poder de los objetos:

 sub some_sub {
    ...
    return Result->new( error => 1, description => ... ) if $something_went_wrong;
    return Result->new( error => 0, ... );
    }

 my $result = some_sub( ... );
 if( $result->is_error ) { ... };

Eso no involucra variables globales, acción a distancia, dolores de cabeza en el alcance, o requiere especiales especiales. Usted crea una clase pequeña Result, o como quiera llamarlo, para ajustar sus valores de retorno para que tenga datos estructurados en lugar de valores únicos sin identidad. Ya no hay dudas de qué significa un valor de retorno. Es eso undef un valor real o una indicación de falla? ¿El valor de retorno es bueno si está definido o si es verdadero? Tu objeto puede decirte estas cosas. Y, puedes usar el mismo objeto con die. Si ya estás usando el objeto con die y usándolo como valor de retorno, hay muy poco que recomiende todas las cosas extra que tienes que hacer para tolerar $@.

Hablo más sobre esto en "Devuelve objetos de error en lugar de arrojar excepciones"

Sin embargo, sé que no puedes ayudar a los demás, así que todavía tienes que fingir que Perl tiene excepciones.


32
2018-04-29 17:28



Siempre fue un caso de preferencia personal. Prefieres

my $rv;
if (!eval { $rv = f(); 1 } ) {
   ...
}

o

my $rv = try {
   f();
} catch {
   ...
};

Pero ten en cuenta que este último usa anon subs, por lo que se mete con return, tanto como next y similares. Try :: Tiny's try-catch bien podría terminar siendo mucho más complicado a medida que agregas canales de comunicación entre el bloque catch y fuera de él.

El mejor escenario (el más simple) para regresar con excepción es si $rv siempre es cierto cuando no hay excepción. Se vería así:

my $rv;
if ($rv = eval { f() }) {
   ...
   return;
}

vs

my $rv = try {
   f();
} catch {
   ...
};

if (!$rv) {
   return;
}

Es por eso que usaría Trata de atraparlo en lugar de Prueba :: Tiny ¿Debo usar ese módulo?

El cambio a Perl simplemente significa que puedes hacer if ($@) de nuevo. En otras palabras,

my $rv;
if (!eval { $rv = f(); 1 } ) {
   ...
}

puede ser escrito

my $rv = eval { f() };
if ($@) {
   ...
}

30
2018-04-28 18:09



Si nada mas, Try::Tiny sigue siendo un buen azúcar sintáctico. Si quieres algo un poco más pesado, también hay TryCatch, lo que resuelve algunos problemas relacionados con el hecho de que las cláusulas de Try::Tiny son subrutinas (por ejemplo, que return no deja la función adjunta).


14
2018-04-28 18:15



Try::Tinyes fácil y ligero. Demasiado fácil. Tuvimos dos problemas:

  • anónimo subs - siempre hubo problemas con 'return'declaración dentro
  • atrapando siempre y todo

Así que hice algunos cambios a Try::Tinyeso nos ayuda Ahora tenemos:

try sub {},
catch 'SomeException' => sub {},
catch [qw/Exception1 Exception2/] => sub {},
catch_all sub {};

Lo sé - esta sintaxis es un poco exótica, pero gracias a evidente 'sub', nuestros programadores ahora saben que'return'statement sale solo del manejador de excepciones, y siempre atrapamos solo las excepciones que queremos atrapar :)


10
2018-04-28 19:03



O lo haces:

local $@;
eval { … }

... para evitar que los cambios en $ @ afecten el alcance global, o use Try :: Tiny.

Sintácticamente, hay situaciones en las que prefiero una u otra.


0
2017-08-22 15:37