How to handle "bad argument in arithmetic expression" error by using guards

I want to learn some basics of this great langauge. I have put this code together:

defmodule Xe do

  def call(input) do
    with {:ok, first} when is_integer(input) <- by_ten(input),
         {:ok, second} <- by_five(first)
    do
      IO.puts second
    else
      _ ->
        IO.puts "error"
    end
  end

  def by_ten(input) do
    {:ok, input * 10} 
  end

  def by_five(input) do
    {:ok, input * 5} 
  end

end

Xe.call("abc")

Here I am getting:

(ArithmeticError) bad argument in arithmetic expression
    a.ex:16: Xe.by_ten/1
    a.ex:5: Xe.call/1
    (elixir) lib/code.ex:677: Code.require_file/2

How to avoid this using guards? Thank you.

guards in with match against the result not the input. So in this case it checks that the result of by_ten first matches {:ok,first} and then runs that against the guard. Put your guard on the function itself to guard against input params. Also make sure to have a by_ten without the guard to return an error.

1 Like

@jordiee

Thank you. Here is the refined code which gives the desired result:

defmodule Xe do

  def call(input) do
    with {:ok, first} <- by_ten(input),
         {:ok, second} <- by_five(first)
    do
      IO.puts second
    else
      _ ->
        IO.puts "error"
    end
  end

  def by_ten(input) when is_integer(input) do
    {:ok, input * 10} 
  end

  def by_ten(_) do
    {:error} 
  end

  def by_five(input) do
    {:ok, input * 5} 
  end

end

Xe.call("abc")

Any remarks are welcome.

1 Like

Yep looks good. The only thing I would change and its really preference is when my function is only one line I change it to shorthand syntax…so

def by_ten(_), do: {:error}

but again that is all preference.

1 Like