[erlang-questions] case expression scope

Anthony Ramine <>
Wed Mar 5 22:12:35 CET 2014

Replied inline.

Anthony Ramine

Le 5 mars 2014 à 21:48, Szoboszlay Dániel <> a écrit :

> On Wed, 05 Mar 2014 03:52:22 +0100, Richard A. O'Keefe <> wrote:
>> Wrong.  Yes, list comprehensions *happen* to be implemented
>> as calls to out-of-line functions, but the *necessity* for
>> list comprehensions to be separate scopes falls directly
>> out of their semantics.
>> Suppose it were otherwise.
>> 	R = [(Y = f(X), Y) || X <- L].
>> What value would X have after the comprehension
>> - if L = []?
>> - if L = [1]?
>> - if L = [1,2]?
>> What value would Y have?
>> The key thing is that X and Y get _different_ values
>> on each iteration, and Erlang variables being immutable,
>> the only way we can make sense of that is if each
>> iteration gets its _own_ X and Y.
> The key thing is list comprehensions introduce a new scope, thus behave different from the rest of the expressions. This is not intuitive, even if it is necessary.
>> In Classic C and C89, *none* of 'if', 'switch', 'while',
>> 'do', and 'for' introduce new scopes.
>> In C99, it's clear from 6.8.4 that 'if' and 'switch'
>> do *NOT* introduce new scopes and it is clear from
>> 6.8.5 that 'while' and 'do' do *NOT* introduce new
>> scopes.
>> In Classic C and C89 the *ONLY* construction that
>> introduces a new scope is '{...}'.
> I don't want to argue with specs, you are technically correct of course. But the mental model is that whenever I introduce a new variable in an if-branch, it will go into a new scope. From the compiler's perspective it's due to the curly braces. From my perspective it's because I want to use that variable in that single block only.

Javascript compilers would love it if scope was just a matter of a pair of curly braces.

From my perspective, the code

	X = ...,

isn’t the same as

	let X = ... in

In the first, « = » does not denote a let-binding of which the resulting augmented environment is used to evaluate its body. It denotes a match expression, which happens to never fail because the pattern matches everything, and of which the environment spills into the next expression « foo(X) ». Given that a match exports variables, why shouldn’t case? if?

I have a patch somewhere which I need to finish, that makes exporting from try possible to, for consistency’s sake.

That being said, if it were just me, I would just forbid the use of all unsafe and exported names. And make fun heads non-shadowing. One True Scope, all the way long.

>> The thing is that Erlang is what it is
>> and is not something else.
>> Criticising Erlang for not being like something else
>> (especially when it turns out that the something else
>> is not in fact like that either)
>> is silly.
> I'm not criticizing Erlang for being what it is. I love this language the way it is already. But I think it could be improved in some areas, and the lack of scoping expressions is one such area. Changing the way case works would be no doubt a terrible decision. Allowing to write code in the style of my examples without breaking backward compatibility would be a useful addition for those who prefer this style.

The lack of scoping expressions is a feature, I don’t want to have to look hard to find the initial binding of a variable, rebinding makes finding the original binding place harder. Also, I find the One True Scope and nonlinear patterns to be quite related and I don’t think it would be nice to have one without the other. Removing nonlinear patterns makes very idiomatic code impossible:

	Ref = erlang:make_ref(),
	Pid ! {request,Ref},
	receive {reply,Ref,Msg} -> ok end.

> If starting a new scope would be as easy in Erlang as in C, I'd be very happy. And why shouldn't it be?

Because we don’t want a new scope.

> For example consider a new expression: "<- Expression" that has the value of Expression but introduces new variables in Expression to a new scope. (OK, probably using the left arrow might have some problems, but at least it looks very Erlangish). Then I could write:
> foo(Dict) ->
>    Value = <- case orddict:find(foo, Dict) of
>                   {ok, Value} -> Value;
>                   error       -> calculate_very_expensive_default_value()
>               end,
>    ...
> (Btw. my problem with "begin ... within ... end" mentioned in a later email is that it is way too verbose. Which is of course also very Erlangish…)

This is certainly not Erlangish because it introduces a new scope even though there is no lambda involved, and because there is no arrow in Erlang which is a prefix or postfix operator. Why would you use an arrow unbalanced?

> And once we are there, there are some other nice tricks we could do with scopes. Consider this real life example: https://github.com/rebar/rebar/blob/master/src/rebar_core.erl#L182-L263 - this function performs a lot of sequential tasks and generates a series of Config variables in the meantime (Config1, Config2, ...). A typical error is that after creating Config123 somewhere later you accidentally use Config122 instead. It would be nice if I could "drop" a variable from the scope and get a compile error if I'd happen to reuse it later. Like this:

Sometimes, the rules in Erlang are just here to make sure your life will be miserable if you get too fancy in a single clause; this is such an occurrence. Also if there were less comments, it would be better in my opinion. And all these newlines, they make my eyes wander all around.

	%% Check that this directory is not on the skip list
	Config7 = case rebar_config:is_skip_dir(Config3, Dir) of

What’s the point of such comments?

> DirSet3 = sets:add_element(Dir, DirSet2),
> ~DirSet2, % Never ever use DirSet2 again!
> ...
> or even:
> DirSet3 = sets:add_element(Dir, ~DirSet2),
> ...
> But I can accept if you think these ideas are worthless as well, only I'd love to hear and discuss your arguments.
> Cheers,
> Daniel
> _______________________________________________
> erlang-questions mailing list
> http://erlang.org/mailman/listinfo/erlang-questions

More information about the erlang-questions mailing list