Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elixir - try/catch vs try/rescue?

Tags:

elixir

Background

Both try/rescue and try/catch are error handling techniques in Elixir. According the corresponding chapter in the introduction guide.

Errors can be rescued using the try/rescue construct

On the other hand,

throw and catch are reserved for situations where it is not possible to retrieve a value unless by using throw and catch.

Doubts

I have a brief understanding that rescue is for errors. While catch is for any value.

However,

  • When should I make use of the error handling mechanisms in Elixir?
  • What are the differences between them in detail?
  • How should I pick one to use in a specific use case?
  • What exactly are 'the situations where it is not possible to retrieve a value unless by using throw and catch'?
like image 719
Gavin Avatar asked Oct 27 '16 09:10

Gavin


1 Answers

It's a good question.After research a bit.

  • What is the differences between them in details?

    José's answer:

Mainly, you should use throw for control-flow and reserve raise for errors, which happens on developer mistakes or under exceptional circumstances.

In Elixir, this distinction is rather theoretical, but they matter in some languages like Ruby, where using errors/exceptions for control-flow is expensive because creating the exception object and backtrace is expensive.

  • How should I pick one to use in a specific use case?

Please check this answer Which situations require throw catch in Elixir

Shortly:

raise/rescue

Consider raise/rescue to be explicitly about exception handling (some unexpected situation like programmer errors, wrong environment, etc).

throw/catch

Is useful in places where you have expected failures. Classic examples are:

  • exiting a deeply nested recursive call:
    https://github.com/devinus/poison/blob/master/lib/poison/parser.ex#L34-L46
  • normal error handling is too expensive (can occur in too many places): https://github.com/michalmuskala/mongodb_ecto/blob/master/lib/mongo_ecto/objectid.ex#L29-L43
  • you have an non-local construct (like transactions): https://github.com/elixir-lang/ecto/blob/428126157b1970d10f9d5233397f07c35ce69cac/test/support/test_repo.exs#L84-L98

The last one:

  • What exactly are 'the situations where it is not possible to retrieve a value unless by using throw and catch'?

Let's say you are trying to running some code from a process that is supervised by a Supervisor but the process dies for an unexpected reason.

try do IO.inspect MayRaiseGenServer.maybe_will_raise rescue   RuntimeError -> IO.puts "there was an error" end 

MayRaiseGenServer is supervised by a Supervisor and for some reason an error was raised:

try do IO.inspect MayRaiseGenServer.maybe_will_raise # <- Code after this line is no longer executed 

And then you can come up with using catch an exception here:

try do   IO.inspect MayRaiseGenServer.maybe_will_raise catch   :exit, _ -> IO.puts "there was an error" end 

Ok.Hope that clarify enough what we are looking for.

like image 164
TheAnh Avatar answered Sep 19 '22 23:09

TheAnh