[erlang-questions] Dyalizer warnings for too wide return type

Kostis Sagonas kostis@REDACTED
Sun Oct 17 18:11:59 CEST 2010


Vincent de Phily wrote:
> On Tuesday 12 October 2010 08:48:57 Alexey Romanov wrote:
>> One problem I have with Dialyzer is that it complains about cases
>> where the return type specified is too wide.
>>
>> E.g.
>>
>> -type handle_cast_return() :: {noreply, tuple()} | {noreply, tuple(),
>> integer()} | {stop, any(), tuple()}.
>> -spec handle_cast(any(), tuple()) -> handle_cast_return().
>> handle_cast(_Msg, State) ->
>>     {noreply, State}.
>>
>> The definition says that handle_cast returns what it is supposed to
>> return according to behaviour, but it gives this warning:
> [...]
>> the given specification satisfies it, and shouldn't result in a
>> warning. Or at least, there should be an option to turn this set of
>> warnings off, and I don't see one in
>> `dialyzer -Whelp`.
> 
> It sounds like -Wunderspecs or -Woverspecs would do that, but that doesn't 
> seem to work. Actually it looks like (contrary to documentation) -Wunderspecs 
> is on by default and we actually need a -Wno_underspecs option.
> 
> But a global no_underspec for the program sounds dangerous too (you'll hide 
> actual underspecs which should be fixed). Maybe dialyzer could ease the pain 
> by handly behaviour spec specially ?
> 
>> -spec some_test() -> boolean().
>> some_test() -> false. %% TODO implement later
>>
>> %% in a different module
>> foo() ->
>>   case m1:some_test() of
>>     true -> ...
>>     false -> ...
>>   end.
>>
>> In addition to the warning about some_test() I get warnings about
>> foo(): "Pattern 'true' can never match type 'false' ", any functions
>> called only from the 'true' branch are reported to be unused, etc.
>> While these warnings are correct, they ignore my specification for
>> some_test(). Can Dialyzer be forced to prefer the return type given in
>> the spec over the` one it infers?
> 
> Yes, that annoys me as well. I understand the warning for the some_spec 
> function, but I think it shouldn't trickle down to the foo function. I have 
> another use-case where I recompile a module at runtime but provide an initial 
> implementation that always returns false.

I could have written a much longer reply in this thread, but I'll keep 
this reply a bit short with the risk of sounding a bit impolite. This is 
not my intention.

The whole discussion above is a bit naive, but perhaps this is primarily 
my fault because there is no document that explains dialyzer's decisions 
and philosophy in general terms. For a long time now I wanted to write a 
"dialyzer FAQ". I hope I can come around to that pretty soon.

Anyway, the short answer is that dialyzer will never do what users may 
initially think it would be better if it did.  The only information that 
dialyzer has to work with is the code and whenever it finds something 
that is a discrepancy between what the code does and what the programmer 
claims it does (e.g. in a spec) it spits a warning about it.  Dialyzer 
cannot be in the minds of programmers and what's their ultimate 
intention even if they add "%% TODO implement later" comments :-)

So, my reply to Alexey's message is that in a situation like the one he 
describes the proper action is to either comment out the true case in 
foo's code or realize that now is the time for this "later".

Now, having written all these, there is a dialyzer option that we have 
primarily added for internal debugging purposes, but may come in handy 
in situations like that. If you want dialyzer to do its analysis based 
on success typings only and ignore the specs of the analyzed modules, 
you can use the option '--no_spec'.

But there is no option "trust the specs, please" for cases where 
dialyzer can determine that they do not correspond to the code. 
Whenever you want to do that, simply don't use dialyzer!


> I'd like dializer to trust me when I declare my interface, even if the 
> implementation doesn't match that. Actually, maybe we could make the case that 
> non-exported functions must have an exact spec whereas exported function can 
> have a spec that is more allowing than the implementation ?

Sorry, but I firmly believe that this last part is wrong. Having 
published interfaces that do not correspond to the implementation is not 
a good idea. Among other things, what sort of confidence do you have 
that the client code works ok? How do you test things in this situation?

Cheers,
Kostis


More information about the erlang-questions mailing list