[erlang-questions] How do I elegantly check many conditions?

Jachym Holecek <>
Fri Mar 20 15:30:32 CET 2009


Hello,

# ryeguy 2009-03-20:
> So when a user sends a request to register an account, they send their
> username, password, email, and other info. The registration function
> must verify all of their data. An example would be:

BTW observe that your tests are of two different kinds:

>  - verify username is alphanumeric
>  - verify all fields are above X characters long
>  - verify all fields are less than Y characters long

These check the shape of incoming data, that is they decide if the
incoming request makes any sense at all.

>  - verify email not in use
>  - verify username not in use

These have a valid request at hand and decide if the system is
able to fulfill it given current state of the world.

It seems like a good idea to keep the two separate in some way. It might
also make some amount of sense to merge the second kind of check with the
actual registration procedure.

> Now I don't want to have a 5 level deep if or case statement, but what
> other options do I have? Splitting it into separate functions sounds
> like a good idea, but then I just have to check the return value of
> the functions in some sort of conditional and it's back to the
> original problem.

I can't see the problem of using nested 'case' expressions, as long
as the resulting code is clear and simple.

> I could separate them into functions and then call an if statement
> with all of the conditionals OR'd together, but that wouldn't give me
> what I want because I need to be able to tell the user the specific
> error if there was one.
> 
> How does one handle this kind of situation in erlang?

I'd probably go with something like the below. But in general, I find
writing partial solutions an extremely confusing task. So, depending
on how the rest of your code works, I might actually go with something
completely different. ;-)

HTH,
	-- Jachym

%% Handle user registration request.
request(Username, Password, Email) ->
    case lists:all(fun in_bounds/1, [Username, Password, Email]) of
	true ->
	    case is_alpha(Username) of
		true ->
		    add_user(Username, Password, Email);
		false ->
		    error
	    end;
	false ->
	    error
    end.

%% Add new user unless his details conflict with existing user. Return 'ok' on success, 'error' on collision.
add_user(Username, Password, Email) ->
    %% XXX If you store users in Mnesia, you'd probably want to write
    %% XXX a check-and-insert function and run that as transaction
    %% XXX instead. It would return a boolean indicating success. If
    %% XXX you're not using Mnesia, you need to deal with the obvious
    %% XXX race condition lurking here yourself :-).
    case is_available(Username, Email) of
	true ->
	    whatever_it_takes_to_add_user(Username, Password, Email),
	    ok;
	false ->
	    error
    end.

%% Decide if string has acceptable length.
in_bounds(String) when length(String) > 3, length(String) < 10 ->
    true;
in_bounds(_) ->
    false.

%% Decide if string is composed of alphanumeric characters.
is_alpha([Char | Rest]) when Char >= $a, Char =< $z ->
    is_alpha(Rest);
is_alpha([Char | Rest]) when Char >= $A, Char =< $Z ->
    is_alpha(Rest);
is_alpha([Char | Rest]) when Char >= $0, Char =< $9 ->
    is_alpha(Rest);
is_alpha([]) ->
    true;
is_alpha(_) ->
    false.



More information about the erlang-questions mailing list