[erlang-questions] Fwd: [erlang-bugs] Incorrect scope for a variable

Robert Virding robert.virding@REDACTED
Fri Feb 18 00:57:09 CET 2011

This is most definitely a bug in the interpreter, erl_eval! The compiler is doing the Right Thing.

The compiler evaluates the code strictly left-to-right which it should do. When we finally got around to actually defining the language we decided define a strict left-to-right evaluation order in expressions. Not because it was necessarily the best, it can preclude compiler optimisations, but because then you would *know* exactly how expressions would be evaluated.

And this is what the compiler does which explains the results from the compiled code.

The interpreter does neither left-to-right nor right-to-left but does try to evaluate them in parallel. So in the case of the expression:

{case 1 of X -> X end, case 2 of X -> X; _ -> 4 end}

it evaluates each case separately with X unbound and then tries to merge the values X of from the two cases. It does something like:

begin V1 = case 1 of X1 -> X1 end, V2 = case 2 of X2 -> X2; _ -> 4 end, X1 = X2, {V1,V2} end

Here X1 and X2 will have different values so the match/test X1 = X2 will fail and generate a 'badmatch' error. N.B. if you were to actually try and write this it would complain that variable X2 is 'unsafe' as it is not exported from both clauses but this rewrite is internal in the compiler.

I personally agree that exporting values from if/case/receive is a Bad Thing (tm) but it does make some code a little more compact. The 'unsafe' error is there to help you detect cases which won't actually be wrong but could otherwise become silently different. Which I can explain in a future message.

So the interpreter is wrong. The fix is actually quite simple.


----- "Joe Armstrong" <erlang@REDACTED> wrote:

> On Thu, Feb 17, 2011 at 3:59 PM, Ola Andersson A <
> ola.a.andersson@REDACTED> wrote:
> > Yes, that is what I would have expected too until I read Joes
> explanation
> > below regarding the same statement in the shell.
> >
> > The question is why the same statement gives a different result in
> the
> > shell as compared to when used in a module:
> >
> Very strange. Consider this module:
> -module(a).
> -compile(export_all).
> foo() ->
>     {case 1 of X -> X end, case 2 of X -> X end}.
> foo1() ->
>     {case 1 of X -> X end, case 2 of X -> X; _ -> 4 end}.
> > a:foo().
> ** exception error: no case clause matching 2
>      in function  a:foo/0
> > a:foo1().
> {1,4}
> The second example shows that order of evaluation withing the tuple
> is left-to-right, if it had been parallel then the result should have
> been
> {1,2}
> (so my earlier explanation was wrong).
> In the shell - both expressions result in errors
> > f().
> ok
> >  {case 1 of X -> X end, case 2 of X -> X end}.
> ** exception error: no match of right hand side value 1
> > f().
> ok
> >  {case 1 of X -> X end, case 2 of X -> X; _ -> 4 end}.
> ** exception error: no match of right hand side value 1
> There is no way I can explain this - the compiled version looks
> correct and
> the version in the shell an error.
> /Joe

Robert Virding, Erlang Solutions Ltd.

More information about the erlang-questions mailing list