I think there is some interesting thought here. I certainly have written my fair share of bang-functions using the case-approach. And while I have no objection in particular against it (it’s only 4 lines after all) this could be a nice little macro exercise.
Disclaimer: As @al2o3cr writes below, using this is probably not a good idea, as it’s a major layer of indirection which will make your codebase harder to reason about. Nevertheless it’s an interesting use-case for macros, so consider this an educational example rather than a production ready one.
defmodule Boom do
defmacro defbang({name, _meta, args}, raising: error) do
quote do
def unquote(:"#{name}!")(unquote_splicing(args)) do
case apply(__MODULE__, unquote(name), unquote(args)) do
{:ok, value} -> value
{:error, reason} -> raise unquote(error), reason
end
end
end
end
end
Which you could then use like this:
defmodule Test do
import Boom
def test(nil), do: {:error, "is nil"}
def test(val), do: {:ok, val}
defbang test(num), raising: ArgumentError
end
Test.test(42)
#=> {:ok, 42}
Test.test("test")
#=> {:ok, "test"}
Test.test(nil)
#=> {:error, "is nil"}
Test.test!(42)
#=> 42
Test.test!("test")
#=> "test"
Test.test!(nil)
#=> ** (ArgumentError) is nil
As mentioned before, I’m not saying that this is a good idea - after all it’s a probably unnecessary layer of indirection - but it’s possible.






















