[erlang-bugs] : bug
Fri Nov 30 13:11:14 CET 2007
Joe Armstrong wrote:
> Actually it was my impression that guard predicates could only occur
> after a "when" keyword or in an "if" and not anywhere else. This is
> consistent with the view that a guard is an extension of pattern matching
> and is there to produce better code in the pattern matcher.
> How is it today? The reference manual on the net says that guard
> sequences can only occur in "if" and after a when - and that guard tests
> are part of guard sequences. It makes no mention of them being allowed in
There are some concepts that need to be properly distinguished:
1. Syntax: "guard", "guard sequence", "guard test"
It is quite correct that syntactically, a guard sequence can only
occur as part of a clause (function, case, if, receive, try) and
only after a 'when' keyword. ("guard" := 'when' "guard sequence")
"guard test" is in part a syntactic concept - it refers to the
individual elements (expressions) in a guard sequence, more
precisely to the outermost operator of each such expression.
2. Scope: which names are defined where, and what semantic objects
do they refer to?
In Erlang, a special rule says that in "guard test" context
(syntactically), some special names are defined which override any
other definitions of those name in the current scope. These are the
"old-style" type tests: integer/1, atom/1, etc. Originally, there
was no way of accessing these functions except from a guard.
For some strange reason, though, you have always been able to use
the tests '=:=', '<', '=<', etc., even outside "guard test" context.
Did you forget to disallow them in normal expressions? ;-)
3. Semantics: regardless of what name you use to identify an operation,
what does it do?
It was not possible, because of the name clashes it would cause,
to make the type tests available in normal expressions under the
same names as in guard test context (like you could for '<'), so
new names had to be introduced. These are the 'is_atom/1' etc.,
but they are just names: they refer to the same operations as
the old guard-context-only names 'atom/1' etc. If you use the new
names they can be accessed everywhere. They also have a home:
they live in the 'erlang' module, along with '+'/2, '<'/2, etc.
So, in summary, if you call 'is_atom/1' from any Erlang expression,
you are _not_ "using a guard test". You are calling a built-in boolean
predicate, which also happens to be _allowed_ in a guard test context.
It is all much simpler if you look at it from that angle.
More information about the erlang-bugs