Why would you create two near-identical functions but one does not have a bang (!)?

I am currently going through the Programming Phoenix book and noticed that the author has two get_user functions:

def get_user(id), do: Repo.get(User, id)
def get_user!(id), do: Repo.get(User, id)

From what I understand today the typical Elixir convention is to affix a ! at the end of a function that could potentially throw but I don’t think the latter one can. Looking at the Ecto.Query docs I know there’s Repo.get! and Repo.get, did the author potentially mean to use that in the latter function?

Thanks for any clarity I can get on my Elixir learning journey!

:fire:h

Typically the conventions are as follows:

fetch: returns {:ok, result} or {:error, error}
fetch!: returns result or raises on not available
get: returns result or nil on not available.

All functions are liable to raise on truly exceptional conditions, for example, it’s legit for a get to raise if there’s no database connection (nil implies not found)

I don’t know why ecto decided to differentiate between get and get! but get! raises on nil (ecto does not provide fetch functions), so you should use get! when the lack of an entry is not an actionable condition and you want to ‘stop the presses’ or ‘stop the assembly line’ (in Toyota six sigma speak)

4 Likes

This looks like a typo - the expectation would be that get_user! would call get!

5 Likes

Bang functions are useful to forego error handling where errors are not supposed to be handled. Personally I see them mostly as a convenience over matching on success cases, with the added benefit of less catching of errors and re-raising on different places (for the match error instead of the original error).

1 Like