How do I elegantly check many conditions in Erlang?

User = get_user(),

Check_email=fun(User) -> not is_valid_email(User#user.email) end,
Check_username=fun(User) -> is_invalid_username(User#user.name) end,

case lists:any(fun(Checking_function) -> Checking_function(User) end, 
[Check_email, Check_username, ... ]) of
 true -> % we have problem in some field
   do_panic();
 false -> % every check was fine
   do_action()
 end

So it isn't 5 level deep any more. For real program i guess you should use lists:foldl for accumulate error message from every checking function. Because for now it simple says 'all fine' or 'some problem'.

Note that in this way add or remove checking condition isn't a big deal

And for "Is there an equivalent of a return statement..." - look at try catch throw statement, throw acts like return in this case.


One of Joe Armstrong's suggestion: program success case code separated from error handling. You can make it in this way

create_user(Email, UserName, Password) ->
  try
    ok = new_email(Email),
    ok = valid_user_name(UserName),
    ok = new_user(UserName),
    ok = strong_password(Password),
    ...
    _create_user(Email, UserName, Password)
  catch
    error:{badmatch, email_in_use} -> do_something();
    error:{badmatch, invalid_user_name} -> do_something();
    error:{badmatch, user_exists} -> do_something();
    error:{badmatch, weak_password} -> do_something();
    ...
  end.

note that you can do all errors catches out of create_user function which is better.

create_user(Email, UserName, Password) ->
    ok = new_email(Email),
    ok = valid_user_name(UserName),
    ok = new_user(UserName),
    ok = strong_password(Password),
    ...
    _create_user(Email, UserName, Password).

main() ->
  try
    ...
    some_function_where_create_user_is_called(),
    ...
  catch
    ...
    error:{badmatch, email_in_use} -> do_something();
    error:{badmatch, invalid_user_name} -> do_something();
    error:{badmatch, user_exists} -> do_something();
    error:{badmatch, weak_password} -> do_something();
    ...
  end.

Pattern match is one of coolest things in Erlang. Note that you can involve your tag to badmatch error

{my_tag, ok} = {my_tag, my_call(X)}

and custom data too

{my_tag, ok, X} = {my_tag, my_call(X), X}

If exception is fast enough for you depends of your expectations. Speed on my 2.2GHz Core2 Duo Intel: about 2 millions exceptions in one second (0.47us) compared to 6 millions success (external) function calls (0.146us) - one can guess that exception handling takes about 0.32us. In native code it is 6.8 vs 47 millions per second and handling can take about 0.125us. There can be some additional cost for try-catch construct which is about 5-10% to success function call in both native and byte-code.

Tags:

Erlang