Guard Expressions raising errors?

using element for example

in Guards:

run(X) when element(1, X) == 1 -> a;
run(_) -> b.

call test(1) will not raise any error
in fact it’s is_tuple(X) andalso element(1, X) == 1?
but have a look this .S file

run(X) when element(1, X) == 1 -> a;
run(X) -> element(1, X).
{function, run, 1, 2}.
  {label,1}.
    {line,[{location,"test.erl",5}]}.
    {func_info,{atom,test},{atom,run},1}.
  {label,2}.
    {bif,element,{f,3},[{integer,1},{x,0}],{x,1}}.
    {test,is_eq,{f,3},[{x,1},{integer,1}]}.
    {move,{atom,a},{x,0}}.
    return.
  {label,3}.
    {line,[{location,"test.erl",6}]}.
    {bif,element,{f,0},[{integer,1},{x,0}],{x,0}}.
    return.

both element call {bif,element,...}, {f,0} raise error?

in Expr

element(1, 1).

obvious, raise error

if it’s strange that it (maybe) has a hidden type check in guard
as far as I know it’s undocumented
and I will write code like these in my work :sweat_smile:

run(Tuple) when is_tuple(Tuple), element(1, Tuple) > 0 -> ...
2 Likes

Errors in guard expressions do not raise an error, that is intended. An error in a guard will simply cause the guard to fail. As documented here (at the end of the section):

If an arithmetic expression, a Boolean expression, a short-circuit expression, or a call to a guard BIF fails (because of invalid arguments), the entire guard fails. If the guard was part of a guard sequence, the next guard in the sequence (that is, the guard following the next semicolon) is evaluated.

7 Likes

Yes, {f,0} means that if the call to element/2 fails, an exception will be raised. {f,0} is used in function bodies.

In guards, {f,FailureLabel} is used (where FailureLabel is a number greater than 0). If the call fails there will be a jump to {label,FailureLabel}.

I recommend that you don’t add unnecessary is_tuple/1 guard tests. It will look confusing for other people reading your code and the compiler will currently not optimise away it.

Also, strictly speaking, using is_tuple(Tuple) is not sufficient to prevent element(1, Tuple) from failing, because element(1, {}) will also fail.

4 Likes

Do not say “guard expression”.
Guards are guards
and expressions are expressions.
It IS documented that any guard that
would have raised an exception had it been an
expression will simply fail quietly.
This applies to ALL guards, not just ones
that involve element(,).
Guards: can only fail, never raise exceptions.
Expressions: can only raise exceptions, never fail.

2 Likes

A guard expression is an expression which is allowed in a guard:
https://www.erlang.org/doc/reference_manual/expressions.html#guard-expressions

2 Likes

Yes, but it’s a dangerously misleading way to talk,
as witness this thread.

1 Like