[erlang-questions] nested variable assignment : bug or the expected behaviour ?

James Churchman jameschurchman@REDACTED
Wed Jun 27 19:54:31 CEST 2012

Thanks everyone, especially Richard Carlsson for that incredibly
detailed response

I now realise that there are some very interesting subtitles to it ..

So that the original {J=200,J}. has no correct meaning unless J is
already bound,  but {J=200,J=200}. will interestingly generate a
pattern match (and succeed in this case)  as will {J=200,J=100} but
obviously fail in this case ! also in all cases the J assignment drops
out of the expression ( just like case statements! and obv as long as
no bad match happened ) which is why the pattern match happens, to
ensure that there is a single value of J that can be bound to ..

finally the pattern patching is only performed at the end of the
expression, not at each place the = is found .. so :

[J=begin erlang:display(1), 100 end, J=begin erlang:display(2), 200
end , J=begin erlang:display(3), 100 end ].

would fail after all 3 sub expressions have been evaluated, giving  "1
2 3 " out , rather than the more expected "1 2" out ..

wow !

Tho yes i do get you point that with excessive use, although the
expression scoping rules are in fact very complex it does prevent
excessively nested variable binding that could lead to difficult to
understand code!


On 26 June 2012 13:05, Richard Carlsson <carlsson.richard@REDACTED> wrote:
> On 06/26/2012 01:55 AM, James Churchman wrote:
>> If i have a function like :
>> f()->[J=100,J].
>> Or put in the shell:
>> {J=200,J}.
>> Or
>> erlang:'+'(J=10,J).
>> Or any other combination of where i try to set a variable nested
>> inside somewhere else, it will say "variable 'J' is unbound" .. is
>> this the expected behaviour ?
> Yes, it's expected. Each expression and subexpression in Erlang has an input
> environment and an output environment (which is the same as the input
> environment unless the expression creates additional bindings). Environments
> are chained so that in the comma-separated body of a clause, the output from
> one expression becomes the input of the next.
> However, arguments to a single expression, such as f(A, B) or {A, B}, are
> always evaluated in the same input environment. Hence, even if you write
> f(X=1, X), where X is a previously unbound variable, both arguments are
> evaluated in the environment that does not contain X, and the compiler
> complains about the second X being unknown.
> The output environment from an expression is the combination of the output
> environments from its subexpressions, so f(X=1, Y=2) exports both X and Y.
> To preserve the constraint that a variable occurring in more than one
> pattern has the same value independent of evaluation order, if you write
> f(X=a(), X=b()), the compiler will actually insert a test after the
> evaluation of the arguments to check that the intermediate results of a()
> and b() are in fact the same value and so either can be taken as the value
> of X.
> As Richard O'Keefe said in his reply, Erlang uses strict left-to-right
> evaluation order also in function arguments (even where it to someone
> writing a compiler might seem to be backwards). This is to ensure that an
> Erlang program behaves the same regardless of compiler implementation, and
> to eliminate a source of confusion: programmers shouldn't have to remember a
> bunch of special cases where evaluation order is right-to-left or undefined.
> What you see is what you get.
> But at the same time, the known evaluation order (with respect to side
> effects) should not be something that programmers can abuse to write
> unreadable code like f(1+g(X=h(Y),42),{foo,X}). Therefore, the scoping rules
> enforce that bindings are effectively treated as if the evaluation order of
> arguments was unknown, or could be changed from one version of Erlang to the
> next without changing the meaning of the program.
>    /Richard

More information about the erlang-questions mailing list