[erlang-questions] Dialyzer: Why do I get a 'will never return success typing error' with this recursive function?

Jeremy Raymond jeraymond@REDACTED
Sat Feb 25 03:38:03 CET 2012


On 2012-02-24, at 3:51 PM, Kostis Sagonas wrote:

> On 02/24/12 19:36, Jeremy Raymond wrote:
>> On Fri, Feb 24, 2012 at 12:07 PM, Kostis Sagonas<kostis@REDACTED>  wrote:
>>> 
>>>  Lesson #2: do not spec function args with terms for which the function will
>>> not return any value.
>> 
>> So my case where I do want the atypical behaviour to loop with some
>> args and no with others, I should forgo the spec and ignore the
>> Dialyzer warning? There is no way I can state via aspecs that this is
>> indeed the intent of the function?
> 
> If your function is indeed like the following one:
> 
> test(noloop) ->
>    ok;
> test(loop) ->
>    test(loop). % dialyzer warns about this call
> 
> then there is a very simple thing that you can do: fold the argument in the function name and make two functions from it:
> 
> test_noloop() ->
>    ok.
> 
> test_loop() ->
>    test_loop().
> 
> Dialyzer knows not to complain about calls to test_loop(), esp. so if you provide a spec that explicitly says that this function has indeed no_return(). To me, this is a more kosher program and expresses what you want better than a spec will do.
> 
> Kostis
> 
> PS. I understand of course that if your program is more involved than the above, you may need to refactor it a bit -- but dialyzer can guide you in this: when it complains that some call will never return, it is sure this call will always end up in the looping clause.
> 

A simplified version of what I'm doing is

work(Type, Args) ->
	spawn_link(fun() -> do_work(Type, Args) end).

do_work(type1, Args) ->
	% do something once
	ok;
do_work(type2, Args) ->
	% do something else, then repeat
	work(loop, Args).

Some types of work are done once, others repeat. I could split the work into different functions, but then I need some other mechanism to select the type of work to do (case or if statements). Is there a better way I can do this?

The actual code is here: https://github.com/jeraymond/leader_cron/blob/master/src/leader_cron_task.erl, spawning work in init/1 and doing the work in run_task/3.


More information about the erlang-questions mailing list