Qual é a diferença entre `raise“ foo ”` e `raise Exception.new (“ foo ”)`?

103

Qual é a diferença - técnica, filosófica, conceitual ou outra - entre

raise "foo"

e

raise Exception.new("foo")

?

John Bachir
fonte

Respostas:

121

Tecnicamente, o primeiro gera um RuntimeError com a mensagem definida como "foo"e o segundo gera uma Exceção com a mensagem definida como "foo".

Praticamente, há uma diferença significativa entre quando você deseja usar o primeiro e quando deseja usar o último.

Simplificando, você provavelmente RuntimeErrornão deseja um Exception. Um bloco de resgate sem um argumento pegará RuntimeErrors, mas NÃO pegará Exceptions. Portanto, se você gerar um Exceptionem seu código, este código não o pegará:

begin
rescue
end

Para capturar o, Exceptionvocê terá que fazer o seguinte:

begin
rescue Exception
end

Isso significa que, em certo sentido, um Exceptioné um erro "pior" do que um RuntimeError, porque você precisa trabalhar mais para se recuperar dele.

Portanto, o que você deseja depende de como seu projeto trata de erros. Por exemplo, em nossos daemons, o loop principal tem um resgate em branco que os captura RuntimeErrors, relata e depois continua. Mas em uma ou duas circunstâncias, queremos que o daemon realmente morra com um erro e, nesse caso, levantamos um Exception, que vai direto ao nosso "código normal de tratamento de erros" e sai.

E, novamente, se você está escrevendo o código da biblioteca, provavelmente deseja um RuntimeError, não um Exception, pois os usuários de sua biblioteca ficarão surpresos se isso gerar erros que um rescuebloco em branco não pode detectar, e eles levarão um momento para perceber o porquê.

Finalmente, devo dizer que RuntimeErroré uma subclasse da StandardErrorclasse, e a regra real é que, embora você possa raise qualquer tipo de objeto, o espaço rescueem branco , por padrão, só capturará qualquer coisa que herde de StandardError. Todo o resto tem que ser específico.

Daniel Lucraft
fonte
2
muito informativo, obrigado. algumas coisas: [1] Esse último parágrafo foi o mais esclarecedor, e deixe-me descobrir em algo IRB você não mencionou: RuntimeError < StandardError < Exception[2] portanto, que segundo bloco de código vai pegar tanto uma exceção e uma RuntimeError [3] é interessante / estranho que o aumento e o resgate "simples" aconteçam para funcionar com aquela Exception em particular [4]. Talvez a regra seja aumentar RuntimeError para o código do cliente, mas aumentar e resgatar as próprias Exceptions personalizadas dentro do próprio código?
John Bachir
1
[1, 2] Sim. [3] não tenho certeza ... [4] Quando estou programando no meu nível mais profissional, tendo a criar tipos de erros personalizados que herdam de StandardError. Não precisa ser mais complicado do que algumas linhas como class MissingArgumentsError < StandardError; end.
Daniel Lucraft
Muito informativo, mas em que tipo de situações você desejará lançar uma Exceção em vez de erro de tempo de execução se o erro de tempo de execução for preferido para escrever bibliotecários?
Chihung Yu
35

Da documentação oficial:

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

Sem argumentos, levanta a exceção em $!ou levanta um RuntimeErrorse $!for nulo. Com um único Stringargumento, ele gera a RuntimeErrorcom a string como uma mensagem. Caso contrário, o primeiro parâmetro deve ser o nome de uma Exceptionclasse (ou um objeto que retorna uma Exceptionexceção quando enviada). O segundo parâmetro opcional define a mensagem associada à exceção e o terceiro parâmetro é uma matriz de informações de retorno de chamada. As exceções são capturadas pela cláusula de resgate de begin...endblocos.

raise "Failed to create socket"
raise ArgumentError, "No parameters", caller
Ennuikiller
fonte