As I was getting chef-server up to speed with dialyzer, I got myself into a little situation, that I couldn’t make heads nor tails of.

If you’ve run dialyzer, you’ve probably seen the dreaded function has no local return error. The first thing I usually do is look at the following few errors. If there’s something nearby, I’ll fix that first. Maybe no local return will go away.

Of course, sometimes you really want the function to have no return. Fortunately, dialyzer provides a type for that: none().

In Learn You Some Erlang's dialyzer chapter, we’re introduced to two most basic types: any() and none(). any() is any erlang term, so it’s not just a clever nickname. none() is tricky. It means that no return type is valid and that this function should crash.

So, why are we talking about it?

I had a function that I knew should have no return. Somewhere down it’s call stack, it calls error/1 which crashes things, and I’m cool with that. But dialyzer told me there was no local return. I KNOW! I told you it was none() so we should be fine with that.

After more time than I care to admit, and scrolling through that same Learn You Some Erlang page, I stumbled across this:

no_return(): this is an alias of none()

Well, if it’s an alias, it should also break. But, desperate times… And it worked. Where none() failed, no_return() succeeded! Let’s look at the code:

%% Dialyzer is ok with this
-spec err(term()) -> none().
err(X) ->
  error({error, X}).

%% dialyzer says this spec has no local return
-spec err_bad(term()) -> none().
%% however, this spec is ok
-spec err_bad(term()) -> no_return().
%% So, there is some difference between none() and no_return()
err_bad(X) ->

When a function called error/1 directly, none() was fine; however, when the function calls a function that calls error/1, only no_return() will get the desired result.

So I emailed Fred about it, which eventually ended with “We should ask Kostis”. And as it so happened, I was soon headed to EUC, which Kostis was also attending. I literally had a gist with this code ready to go on my phone, should the opportunity to ask about it arise.

As it turns out, it did! The answer straight from Kostis, is that none() and no_return() should be equivalent. If they’re not, it’s an issue with the implementation (read: I found a bug in dialyzer!), but it doesn’t matter, just always use no_return().

So, there you have it. none() is for chumps. no_return() 4 lyfe.