Guards & Conditional Expressions
Guard expressions are restricted to side-effect-free operations: type tests, comparisons, arithmetic, boolean operators, and BIFs like abs, element, hd, tl, length, map_size, tuple_size, byte_size, bit_size, is_map_key, map_get, node, self, round, trunc, fl…
8.1 Guards
Guard expressions are restricted to side-effect-free operations: type tests, comparisons, arithmetic, boolean operators, and BIFs like abs, element, hd, tl, length, map_size, tuple_size, byte_size, bit_size, is_map_key, map_get, node, self, round, trunc, float, min, max (OTP 26+), binary_part. You cannot call your own functions in guards.
Errors in guards make the guard fail (no exception).
classify(N) when is_integer(N), N < 0 -> negative; % , means AND
classify(0) -> zero;
classify(N) when is_integer(N) -> positive;
classify(N) when is_float(N); is_atom(N) -> other. % ; means OR8.2 case
If no clause matches → case_clause error.
describe(Value) ->
case Value of
{ok, Result} -> io:format("Success: ~p~n", [Result]);
{error, Reason} when is_atom(Reason) -> io:format("Error: ~p~n", [Reason]);
_ -> io:format("Unknown~n")
end.8.3 if (guard-based)
if branches use guards only (no function calls). If no branch matches → if_clause error.
temperature(T) ->
if
T < 0 -> freezing;
T < 20 -> cold;
T < 30 -> warm;
true -> hot % "else" branch
end.8.4 Everything is an expression
Variables bound in some branches of a case but not others are "unsafe" — the compiler warns. Bind in all branches or return values.
Status = case X > 0 of
true -> positive;
false -> non_positive
end.8.5 maybe expression (OTP 25+, default in 27)
?= short-circuits: if the match fails, the non-matching value is returned (or handled by else).
-feature(maybe_expr, enable). % needed in OTP 25/26 only
process(Input) ->
maybe
{ok, Parsed} ?= parse(Input),
{ok, Valid} ?= validate(Parsed),
{ok, save(Valid)}
else
{error, Reason} -> {error, Reason}
end.