47

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.

Marc
  • 4,820
  • 3
  • 38
  • 36

3 Answers3

49

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
0xAX
  • 20,957
  • 26
  • 117
  • 206
  • Thanks for taking the time to provide a good example from the source of Phoenix. It answers my question perfectly. I was stuck between your answer and the one I picked because both explained my question well. I chose not to select this one only because it focused on Phoenix's use of the `!` and, unfortunately not expressed in my question, I'm interested in Elixir conventions somewhat more than Phoenix. – Marc Oct 26 '15 at 14:25
  • 1
    I'm going to eat my own words - and accept your answer because it points out an important detail as mentioned by @MoxleyStratton - "The bang convention applies to situations where there are two versions of a function-- one that raises an exception (the bang version), and one that doesn't." – Marc Nov 18 '16 at 13:22
18

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.

Community
  • 1
  • 1
coderVishal
  • 8,369
  • 3
  • 35
  • 56
  • Thank you for finding the reference I had been looking for here on SO. I had hoped that what you'd linked would have some references to official documentation but I guess it will have to do. I'm coming from a python world full of PEP articles and such where more than a couple paragraphs are dedicated to the "why's", so I'm a little let down that the same public thought process isn't available, but this will have to do. – Marc Oct 26 '15 at 14:20
  • happy to help, and also elixir is new and improving every day, including the documentation. So I think the docs,soon will reach the level that expect of them. – coderVishal Oct 26 '15 at 17:10
  • 1
    I'm still very grateful for the source you pointed out, however, now (looking back) I've moved the correct answer to @0xAX because of the emphasis placed on dual versions of a function. I hope you agree with the decision. – Marc Nov 18 '16 at 13:26
2

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)

GavinBrelstaff
  • 3,016
  • 2
  • 21
  • 39
  • My main problem is that the documentation is made in passing and we as the Elixir community are expected to catch on the subtleties. I'm glad I was able to glean something and that you provided the `community documentation` of its accepted use :) TY – Marc Oct 26 '15 at 14:29
  • 2
    I find this answer to be misleading. Reading it, a developer could conclude that when creating a function that raises an error, it should be named with a bang (!). That's not the intent of the bang convention. @0xAX got it right that upon seeing a bang function that "it means that likely there is a function with the same name, but without ! symbol". The bang convention applies to situations where there are two versions of a function-- one that raises an exception (the bang version), and one that doesn't. – Moxley Stratton Nov 17 '16 at 23:08
  • @MoxleyStratton looking back on this question (and accepted answer) I agree with you (and disagree with my past decision ). – Marc Nov 18 '16 at 13:19