[erlang-questions] Dialyzer bug or some problem with my code

Kostis Sagonas <>
Tue Mar 22 01:26:46 CET 2011


Anthony Molinaro wrote:
> Hi,
> 
>   Not sure if this is a bug or not, but the attached file exhibits the
> following.
> 
> % erlc tmp.erl
> % erl -eval 'tmp:test(), init:stop()' -noshell
>   All 2 tests passed.
> % dialyzer -Wno_opaque tmp.erl
>   Checking whether the PLT /Users/molinaro/.dialyzer_plt is up-to-date... yes
>   Proceeding with analysis...
> tmp.erl:19: Function key_in_dict/2 has no local return
> Unknown functions:
>   eunit:test/1
>  done in 0m0.63s
> done (warnings were emitted)
> 
> Using R14B02.  As far as I can tell the key_in_dict function always returns
> so I'm not sure why it would have no local return.  I can always work around
> with -Wno_return but I already don't like the fact that I have to work around
> dict being an opaque type with -Wno_opaque (is that ever going to get fixed?).

You've put yourself in a corner and now you are wondering why you are 
there...

The option -Wno_opaque does not mean what you think it means: it simply 
shuts off all dialyzer *warnings* about opacity violations in your code. 
But it does not make dialyzer change its default behavior, which is to 
consider all opacity violations as failures.

Without this option, dialyzer complains that:

tmp.erl:11: The call tmp:key_in_dict(A::any(),Dict::tuple()) does not 
have an opaque term of type dict() as 2nd argument
tmp.erl:19: Function key_in_dict/2 has no local return
tmp.erl:20: The call 
dict:is_key(Key::maybe_improper_list(),Dict::tuple()) does not have an 
opaque term of type dict() as 2nd argument

and it's exactly the warning in line 20 which makes dialyzer think that 
you are doing something wrong there.  For better or worse, dict() is 
defined as an opaque data type, in the Erlang documentation also, which 
means that you should not really inspect its structure with type tests 
and element/1 like you do in your code:

in_thing (A, B) ->
   case B of
     Dict when is_tuple (B) andalso element (1, B) =:= dict ->
       key_in_dict (A, Dict);
     List when is_list (B) ->
       key_in_list (A, List);
     _ ->
       false
   end.

In your case you can cheat a bit and "have your cake and eat it too", if 
you are willing to come to terms that the "let it fail" philosophy is 
actually a good design principle and your code should not just return 
false if you happen to pass something unexpected to the second argument 
of in_thing/2. You can then write your code as:

in_thing (A, B) ->
   case B of
     List when is_list (B) ->  % IMO: this should read is_list(List) here
       key_in_list (A, List);
     Dict ->
       key_in_dict (A, Dict)
   end.

which does NOT inspect the structure of dict().

Dialyzer will then start liking you more. ;)

Kostis


More information about the erlang-questions mailing list