¿Cuál es la diferencia entre `raise" foo "` y `raise Exception.new (" foo ")`?

103

¿Cuál es la diferencia - técnica, filosófica, conceptual o de otro tipo - entre

raise "foo"

y

raise Exception.new("foo")

?

John Bachir
fuente

Respuestas:

121

Técnicamente, el primero genera un RuntimeError con el mensaje configurado en "foo", y el segundo genera una Excepción con el mensaje configurado en "foo".

En la práctica, existe una diferencia significativa entre cuándo desearía usar el primero y cuándo desea usar el segundo.

En pocas palabras, probablemente quieras un RuntimeErrornot an Exception. Un bloque de rescate sin un argumento capturará RuntimeErrors, pero NO capturará Exceptions. Entonces, si genera un Exceptionen su código, este código no lo detectará:

begin
rescue
end

Para atraparlo Exceptiontendrás que hacer esto:

begin
rescue Exception
end

Esto significa que, en cierto sentido, an Exceptiones un error "peor" que a RuntimeError, porque tiene que trabajar más para recuperarse.

Entonces, lo que quieras depende de cómo tu proyecto maneje los errores. Por ejemplo, en nuestros demonios, el bucle principal tiene un rescate en blanco que los detectará RuntimeErrors, los reportará y luego continuará. Pero en una o dos circunstancias, queremos que el demonio realmente muera por un error, y en ese caso generamos un Exception, que pasa directamente por nuestro "código normal de manejo de errores" y sale.

Y nuevamente, si está escribiendo código de biblioteca, probablemente desee un RuntimeError, no un Exception, ya que los usuarios de su biblioteca se sorprenderán si genera errores que un rescuebloque en blanco no puede detectar, y les llevará un momento darse cuenta de por qué.

Finalmente, debo decir que RuntimeErrores una subclase de la StandardErrorclase, y la regla real es que, aunque puede raise cualquier tipo de objeto, el espacio en blanco rescuesolo capturará por defecto cualquier cosa que herede StandardError. Todo lo demás tiene que ser específico.

Daniel Lucraft
fuente
2
muy informativo, gracias. un par de cosas: [1] Ese último párrafo fue el más esclarecedor, y me dejó descubrir algo IRB que no ha mencionado: RuntimeError < StandardError < Exception[2], por lo tanto, que el segundo bloque de código va a coger tanto una excepción y un RuntimeError [3] Es interesante / extraño que la subida y el rescate "desnudos" funcionen con esa Excepción en particular [4]. Quizás la regla general sea elevar RuntimeError al código del cliente, pero ¿generar y rescatar las propias Excepciones personalizadas dentro del propio código?
John Bachir
1
[1, 2] Sí. [3] no estoy seguro ... [4] Cuando estoy codificando en mi forma más profesional, tiendo a crear tipos de error personalizados que heredan StandardError. No tiene por qué ser más complicado que unas pocas líneas como class MissingArgumentsError < StandardError; end.
Daniel Lucraft
Muy informativo, pero ¿en qué tipo de situaciones querrá lanzar una excepción en lugar de un error de tiempo de ejecución si se prefiere el error de tiempo de ejecución para escribir libraray?
Chihung Yu
35

De la documentación oficial:

raise   
raise( string )
raise( exception [, string [, array ] ] )

Sin argumentos, genera la excepción en $!o genera un RuntimeErrorif $!es nil. Con un solo Stringargumento, genera un RuntimeErrorcon la cadena como mensaje. De lo contrario, el primer parámetro debe ser el nombre de una Exceptionclase (o un objeto que devuelve una Exceptionexcepción cuando se envía). El segundo parámetro opcional establece el mensaje asociado con la excepción y el tercer parámetro es una matriz de información de devolución de llamada. Las excepciones están atrapadas por la cláusula de rescate de begin...endbloques.

raise "Failed to create socket"
raise ArgumentError, "No parameters", caller
ennuikiller
fuente