[erlang-questions] How about a new warning? Was: Re: trouble with erlang or erlang is a ghetto
Richard Carlsson
carlsson.richard@REDACTED
Fri Aug 5 10:47:29 CEST 2011
On 08/05/2011 04:22 AM, Jeff Schultz wrote:
> The difference between the two cases seems a bit weird to me. I would
> have expected that the meaning of a call f(Expr1, Expr2) (I'll write
> it as |f(Expr1, Expr2)|) where the Expr are other Erlang expressions
> should be exactly the same as
>
> |T1 = Expr1|,
> |T2 = Expr2|,
> f(T1, T2)
>
> where the T are new variables and |.| is applied recursively.
>
> In this case, |(X = 8) + X| means X = 8, T1 = X, T2 = X, T1 + T2,
> which is okay, and |X + (X = 8)| means T1 = X, X = 8, T2 = X, T1 + T2,
> which is a compile-time error.
>
> While I appreciate the intent of Barklund's rule above, I don't think
> it plays well with Erlang's explicit left-to-right order of
> evaluation.
I think you have misunderstood something - or maybe I'm missing
something in your reasoning. Barklund's stated rule means that |(X = 8)
+ X| is just as invalid in Erlang as |X + (X = 8)|, because even though
it will work in a left-to-right evaluation order (which is ultimately
the order in which the arguments _will_ be executed), it will not work
in _any_ evaluation order. The compiler therefore rejects it.
The nice consequence is that you can always naively reorder the
arguments of a function or operator call (in a valid program), because
there's no possibility that one affects the variable bindings expected
of another.
Hence, the rule actually plays very _well_ with the explicit evaluation
order: it says that even though it's tempting to think it would be good
to allow this kind of variable propagation since the evaluation order is
strictly left-to-right anyway, that's not a good idea, because it
actually makes programs harder to reason about and harder to refactor
without introducing bugs.
The general linearization of f(Expr1, Expr2) can be expressed as:
%% *if* Expr1 and Expr2 don't depend on each other's bindings:
T1 = Expr1,
T2 = Expr2,
%% for all X,Y,... exported from both Expr1 and Expr2:
X1 = X2, Y1 = Y2, ... % ensure they are the same
f(T1, T2)
(of course, the check of bindings only happens in extremely rare cases
like my example f(X=8, X=8), so there's normally no overhead for this).
Of course, side effects in argument expressions are a different matter.
An expression like f(P ! foo, P ! bar) will _always_ cause foo to arrive
before bar at P, because the evaluation order is fixed. And naively
reordering arguments with side effects in them could easily screw up
your program - which is why having side effects in arguments is bad style.
/Richard
More information about the erlang-questions
mailing list