How to handle this if statements?

I have this bunch of if statements.

  if a != 0  do
      {:ok, "can be done"}
  else
      if  b != 0  do
       {:ok, "can be done"}
      else
        {:error, "can not be done"}
      end
   end

I want to add one more condition here that will not have a value greater than 10. If it has greater than 10 I have to throw some error. and I don’t want to add another else statement here.
Is there any other way using a case or cond from which we can handle this better?

cond is your friend,
with may also be.

1 Like

Cond is definitely a good choice here:

cond do
  a != 0 -> {:ok, "can be done"}
  b != 0 -> {:ok, "can be done"}
  true -> {:error, "..."}
end
2 Likes

if I do this using cond

cond do
  a != 0 -> {:ok, "can be done"}
  a >= 10 -> {:error, "can't"}
  b != 0 -> {:ok, "can be done"}
  b >= 10 -> {:error, "can't"}
end

this will not work, right? I have not tried this but something like this I want. It should always check the condition with a. if a is 0 then only it can move to b.
similary if a failed then it shouldn’t check the condition with b

Is this your real logic or an example? I’m having a bit of a difficult time suggesting things because I’m not quite following the purpose of the logic.

Its an example.

The example code you posted could be solved with a simple if, but if you want to avoid running more expensive calculations and validate the results then I think you want with, because as soon as one statement fails, it will skip the rest.

with a_success <- a_check, b_success <- b_check do
  result
else
  error
end

If you don’t need to pattern match against the results then you could probably still just use a simple if with boolean operators.

Are you able to provide some of your actual code? I believe we will be able to provide better answers if we can see real code.

4 Likes

Since there seem to be only two branches, why not something like this:

valid = (a != 0 && a <= 10) || (a == 0 && b != 0)

if valid do
  ...
end

If you want to raise on a > 10 then I’d go with cond:

cond do
  a > 10 -> raise ArgumentError, "a > 10"
  (a != 0) || (a == 0 && b != 0) -> {:ok, "can be done"}
  true -> {:error, "can not be done"}
end

or a separate clause for that:

if a > 10, do: raise ArgumentError, "a > 10"

valid = ...

cond will return on the first true condition, x != 0 is always true when x >= 10 so these lines will never match.

iex(1)> fun = fn a,b -> cond do
...(1)>     a != 0 -> {:ok, "can be done, a != 0"}
...(1)>     a >= 10 -> {:error, "can't, a >= 10"}
...(1)>     b != 0 -> {:ok, "can be done, b != 0"}
...(1)>     b >= 10 -> {:error, "can't, b >= 10"}
...(1)>   end
...(1)> end
#Function<43.65746770/2 in :erl_eval.expr/5>
iex(2)> fun.(0, 0)
** (CondClauseError) no cond clause evaluated to a truthy value

iex(2)> fun.(1, 0)
{:ok, "can be done, a != 0"}
iex(3)> fun.(0, 1)
{:ok, "can be done, b != 0"}
iex(4)> fun.(11, 0)
{:ok, "can be done, a != 0"}
4 Likes