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

Joe Armstrong <>
Fri Feb 18 13:39:57 CET 2011


On Fri, Feb 18, 2011 at 10:32 AM, nox <> wrote:

> I don't understand why would you find it more compact. Can't you just bind
> case result?
>



It's all about denoting scope.

In erlang the scope of a variable is from the first point it is
bound, to the last point it is used. This means we can have
non-nested scopes.The alternative would be

   let {X,Y,Z} = foo(...) in
       begin

           ...
       end,

*all* the variables X,Y,Z live to the end of the begin..end block.  So even
if we've
finished with X early on in the scope we can't garbage collect it.

In erlang variables live from the point where they are first bound to the
point where they
are last used.

If two possible paths thorough the program lead to situation where a
variable
might have different values, then the variable is compared for equality. The
compiler
rejects programs where there are multiple paths through a program which can
create sets of new variables, where these sets are not identical in all
paths - these
are the "unsafe" variables, ie variables that only occur in some paths
through the code
but not others.

All of this might sound complicated, but is designed to make the programs
small
and easy to read.

This follows the prolog tradition from whence erlang grew.

/Joe





> Le 18 févr. 2011 à 00:57, Robert Virding <
> > a écrit :
>
> > 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.
> >
> > Robert
> >
> >
> >
> > ----- "Joe Armstrong" <> wrote:
> >
> >> On Thu, Feb 17, 2011 at 3:59 PM, Ola Andersson A <
> >> > 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.
> >
> >
> > ________________________________________________________________
> > erlang-questions (at) erlang.org mailing list.
> > See http://www.erlang.org/faq.html
> > To unsubscribe; mailto:
> >
>


More information about the erlang-questions mailing list