On 06/20/2013 06:07 PM, Anthony Ramine wrote:
> I don't believe they do in places where guards are the only inhabitant.
>> I do believe they violate it in comprehensions; call these two functions with [foo]:
>> F = fun (L) -> [ X || X <- L, X rem 2 =:= 0 ],
> G = fun (L) -> [ X || X <- L, _ = X rem 2 =:= 0 ].
>> Regards,
>
You omitted the "end"s - but you obviously didn't mean to do that.
OK - so you just blew my mind. What is happening here? Let me see if I
can explain it:
In F, the "X rem 2" guard fails because X is not an integer - but it is
in a guard context, so no error is produced, the guard just evaluates to
false, and F([foo]) returns [].
In G, the "X rem 2" is in the rhs of an "assignment" - really a match
expression: that is no longer a guard context, so G([foo]) produces an
error instead.
Does that sound right?
Personally, I would stay away from using this
false-not-error-on-bad-type behavior of guards that are not patterns.
It's easy enough to use the is_type BIFs to make the meaning explicit
and far less astonishing:
H = fun (L) -> [X || X <- L, is_integer(X), X rem 2 =:= 0] end.
But, then I'm writing Erlang code that I expect to be read and
understood by non-Erlang programmers.
Is Dialyzer (or some other lint-like Erlang tool) customizable? If so,
I'd like to add a customization that flags such cases for my own use.
-- Jonathan