Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are Elixir Bang Functions?

I first noticed a function with a trailing exclamation-mark/bang(!) while going through the Phoenix tutorial (in the Incoming Events section)

def handle_in("new_msg", %{"body" => body}, socket) do
    broadcast! socket, "new_msg", %{body: body}
    {:noreply, socket}
end

What does the trailing exclamation mark mean? Does it do anything? I've been searching around and tried looking but I'm not sure I'm using the right terms. So far it seems that the function only as convention will raise an error if it fails, but does always it always mean that.

The only mentions I see of it appear in "Programming Elixir" by Dave Thomas:

Identifiers in Elixir are combinations of upper and lower case ASCII 
characters, digits, and underscores. Function names may end with a 
question mark or an exclamation point.

And also in the documentation it mentions:

Notice that when the file does not exist, the version with ! raises an
error. The version without ! is preferred when you want to handle
different outcomes using pattern matching...

Neither of these explains if this is a convention that other elixirists or alchemists or whatever use. Please help.

like image 202
Marc Avatar asked Oct 24 '15 23:10

Marc


3 Answers

This:

Notice that when the file does not exist, the version with ! raises an error. The version without ! is preferred when you want to handle different outcomes using pattern matching...

will be more clear if you will look at the source code. The ! symbol in a function name is just a syntactic agreement. If you see a function which contains the ! symbol in its name, it means that likely there is a function with the same name, but without ! symbol. Both of these functions will do the same thing, but they will handle errors in a different way.

The function without ! will just return an error to you. You will be need to know a type of error and handle it depends on your type. Look on the broadcast/3 function (variant without !):

  def broadcast(server, topic, message) when is_atom(server),
    do: call(server, :broadcast, [:none, topic, message])

It just makes call to the given server and will return its result. The broadcast!/3 function will do the same, but: it will call broadcast function without !, will check its result and raise the BroadcastError exception:

  def broadcast!(server, topic, message) do
    case broadcast(server, topic, message) do
      :ok -> :ok
      {:error, reason} -> raise BroadcastError, message: reason
    end
  end
like image 151
0xAX Avatar answered Oct 22 '22 15:10

0xAX


Its just a naming convention. Check this answer out - What's the meaning of "!", "?", "_", and "." syntax in elixir

! - Will raise an exception if the function encounters an error.

One good example is Enum.fetch!(It also has a same Enum.fetch which does not raise exception).Finds the element at the given index (zero-based). Raises OutOfBoundsError if the given position is outside the range of the collection.

like image 34
coderVishal Avatar answered Oct 22 '22 14:10

coderVishal


You basically got it right Marc - it is a convention to say DO RAISE AN ERROR if things go wrong.

There is documentation, of a kind, on this page that talks about File access (scroll down to the phrase trailing bang)

like image 2
GavinBrelstaff Avatar answered Oct 22 '22 13:10

GavinBrelstaff