Why is this guard not throwing an exception?

Consider the following code:

-module(abc). -export([f/1]). f(X) when (X==0) or (1/X>2) -> X+100; f(X) ->X. 

and abc: f (0). get the result 0, but why doesn't 1 / X throw an exception?

+4
source share
2 answers

The erlang documentation's Guard Sequences section says:

If an arithmetic expression, a logical expression, a short circuit expression, or a call to the protective BIF fails (due to invalid arguments), all protection fails. If the guard was part of a guard sequence, the next guard in the sequence (that is, the guard following the semicolon) will be evaluated.

In other words, the exceptions in the guards are treated as if the defender returned false without raising the exception. The guards score is slightly different from the normal erlang expressions.

When you call abc:f(0) , the expression (0==0) or (1/0>2) . This expression "fails" due to division by zero, so the protection does not match, and the next sentence is evaluated to give an answer of 0 .

If you want this case to return 100 , you have two options: use a protection sequence or use logical operators with a short circuit. That would be

 f(X) when X==0; 1/X>2 -> X + 100; f(X) -> X. 

and

 f(X) when X==0 orelse 1/X>2 -> X + 100; f(X) -> X. 

respectively. Both writing methods will evaluate X==0 as a separate exception and not execute 1/X>2 if the result is correct.

+6
source

See here for documentation. To select and specify:

A guard consists of a sequence of tests, not expressions, and the test will be either successful or unsuccessful, if there is an error in the test, it will not throw an exception that it just fails.

In a guard, you can have a guard sequence, which is a sequence of guards separated by a symbol ; if one of the guards succeeds, then the entire defense sequence completes successfully. Thus ; shares alternative protective devices.

There may be a sequence of defensive tests in the defender, separated , all tests in the guard must succeed for the success of the entire defender. So, the most common guard will be:

 f(...) when <test11>, <test12> ; <test21>, <test22> ; ... -> 

What about Boolean operators and how they relate to tests,, and ; ? It is completely legal to use logical operators in security tests, and they behave as expected, BUT they do not match the usage , and ; . Especially regarding the refusal. Thus, the logical expression <test11> and <test12> is just one , not a sequence of two. More importantly, <test11> or test<21> (or using orelse ) still remains one defensive test, not a sequence of two guards. Thus, an error in <test11> will cause all protection to fail. While with <test11> ; < test21> <test11> ; < test21> error in <test11> will fail, the security test will be checked, and the alternative protector <test21> will be checked.

This is the reason for the recommendations in the comment mentioned by @ShiDoiSi. You can use them, but keep in mind what they mean and how they behave. And remember : protection consists of tests, not expressions.

PS Some story about why this is so. It is very simple: we had guards long before we had logical operators, so when we finally got the logical operators, the semantics of the guards were already well defined and it was too late to change. By providing logical expressions in protective devices, you can write more accurate guards, they tend to hide the true nature of the guards.

+4
source

All Articles