[erlang-questions] A dialyzer question on improper list detection of list appends

Kostis Sagonas kostis@REDACTED
Thu Aug 19 21:46:04 CEST 2010


Jesper Louis Andersen wrote:
> I have some code which goes like this (in gproc):
> 
> qlc_next(_, '$end_of_table') -> [];
> qlc_next(Scope, K) ->
>     case ets:lookup(?TAB, K) of
>         [{{Key,_}, Pid, V}] ->
>             [{Key,Pid,V} | fun() -> qlc_next(Scope, next(Scope, K)) end];
>         [] ->
>             qlc_next(Scope, next(Scope, K))
>     end.
> 
> The dialyzer does not like it, it reports:
> 
> gproc.erl:1149: Cons will produce an improper list since its 2nd
> argument is fun(() -> maybe_improper_list({_,_,_},fun(() ->
> maybe_improper_list(any(),fun(() -> any()) | [])) | []))
> 
> This is entirely true and the warning is in addition good. Improper
> lists is somewhat of a mistake :) Since this is a problem in general
> with QLCs, and qlc_next/1 I wondered how it was fixed for, say, ETS
> tables in Erlang. In lib/stdlib/src/ets.erl we find:
> 
> qlc_next(_Tab, '$end_of_table') ->
>     [];
> qlc_next(Tab, Key) ->
>     ets:lookup(Tab, Key) ++ fun() -> qlc_next(Tab, ets:next(Tab, Key)) end.
> 
> Hmm, clever! So I change the code from gproc to:
> 
> @@ -1157,7 +1146,7 @@ qlc_next(_, '$end_of_table') -> [];
>  qlc_next(Scope, K) ->
>      case ets:lookup(?TAB, K) of
>          [{{Key,_}, Pid, V}] ->
> -            [{Key,Pid,V} | fun() -> qlc_next(Scope, next(Scope, K)) end];
> +            [{Key,Pid,V}] ++ fun() -> qlc_next(Scope, next(Scope, K)) end;
>          [] ->
>              qlc_next(Scope, next(Scope, K))
>      end.
> @@ -1166,7 +1155,7 @@ qlc_prev(_, '$end_of_table') -> [];
>  qlc_prev(Scope, K) ->
>      case ets:lookup(?TAB, K) of
>          [{{Key,_},Pid,V}] ->
> -            [{Key,Pid,V} | fun() -> qlc_prev(Scope, prev(Scope, K)) end];
> +            [{Key,Pid,V}] ++ fun() -> qlc_prev(Scope, prev(Scope, K)) end;
>          [] ->
>              qlc_prev(Scope, prev(Scope, K))
>      end.
> 
> and magically, the Dialyzer warning disappears. Now the million dollar
> question is: Why? Both are equivalent improper lists, right? Maybe
> Kostis or someone else with dialyzer-fu can shed some light on this?

It's really very very simple.

Pay attention to the fine line of the warning: "Cons will produce ..."
In the ++ case there is no explicit cons involved ;-)

Now, can I have my million dollars? :)

Seriously though, the core of the problem is that you are making an 
assumption which does not hold. You are implicitly assuming that 
dialyzer is a tool which is *sound for correctness*: i.e., capable of 
detecting a complete set of warnings (of a certain kind). It is NOT. 
It's explicitly designed to be a tool which is *sound for defect 
detection*: i.e., it will never give you a false warning but you have no 
guarantee that it will give you all warnings. (Granted of course that in 
this particular case, it's damn easy to special-case ++/2 also, and 
indeed we might do this when and if we feel like it... not likely to 
happen soon though, so you are safe for the time being.)

Cheers,
Kostis


More information about the erlang-questions mailing list