[erlang-questions] variable exported from case in OTP 18

zxq9 zxq9@REDACTED
Tue Sep 29 13:42:19 CEST 2015


On 2015年9月29日 火曜日 11:06:48 Martin Koroudjiev wrote:
> Hello,
> 
> I am confused why this code generates warning with the warn_export_vars
> option:
> 
> -module(test).
> 
> -export([test/1]).
> 
> test(Mode) ->
>     case Mode of
>         r -> {ok, FP} = file:open("warn.erl", [read]);
>         w -> {ok, FP} = file:open("warn.erl", [write])
>     end,
>     file:close(FP).
> 
> compile:file("test.erl", [report, warn_export_vars]).
> test.erl:10: Warning: variable 'FP' exported from 'case' (line 6)
> {ok,test}
> 
> Why this is better than this code:
> 
> test(Mode) ->
>     {ok, FP} =
>         case Mode of
>             r -> file:open("warn.erl", [read]);
>             w -> file:open("warn.erl", [write])
>         end,
>     file:close(FP).
> 
> which produces no warnings?

`case`, `if`, comprehensions, etc. are assumed to introduce a new scope of their own (whether they *actually* do or not). From this view you are accessing a variable defined within a different conceptual scope, even if it actually is accessible in this particular case.

The reason this has been made into a warning (and many tools compile with warnings-as-errors set) is that it is possible to not assign a variable you access outside the case in every branch of it and still get a clean compile:

foo() ->
    case bar() of
        {bing, Spam} -> eat(Spam);
        {bong, Eggs} -> eat(Eggs)
    end,
    puke(Spam).

VS

foo() ->
    Food = case bar() of
        {bing, Spam} -> Spam;
        {bong, Eggs} -> Eggs
    end,
    ok = eat(Food),
    puke(Food).

Hey, look, one is more likely to be self-documenting now...

This has been discussed several times (here, for example: http://erlang.org/pipermail/erlang-questions/2014-March/078017.html), and because of the weirdness of case scope being one way (its a scope semantically and conceptually, but its not really) and list comprehensions being another (it really is a separate scope, but that's not how some other languages work) this has been made into a warning.

I remember the warning/error discussion happening, but can't find the notes for it (I had thought the "this is always a warning" thing came up with R16 or 17...?). :-( Anyway, what I remember of it was the danger of not assiging a variable in every branch, that being a silly thing to even worry with since cases are sorta-kinda their own scope, and case statements have a return value anyway that should be used as per the way everything else in Erlang works.

-Craig



More information about the erlang-questions mailing list