20

I often see Erlang functions return ok, or {ok, <some value>}, or {error, <some problem>}.

Suppose my function returns an integer N. Should my function return just N, or {ok, N}?

Or suppose my function includes the call io:function("Yada yada"). Should it return ok or nothing at all?

Or suppose I'm making a record or fun. Should I return {ok, R} or (ok, F}?

Thanks,

LRP

legoscia
  • 39,593
  • 22
  • 116
  • 167
Lloyd R. Prentice
  • 4,329
  • 3
  • 21
  • 31

3 Answers3

27

It's a matter of style, but making reasonable choices goes a long way toward making your code more readable and maintainable. Here are some thoughts based on my own preferences and what I see in the standard library:

  • If the function can return with both a success and a recoverable failure case, you may want the success case to look like {ok, _} or ok. Good examples are: orddict:find/2 and application:start/1. We do this so both cases can be easily pattern matched when making the call.
  • If the function has only a success case with a meaningful result, then just return the result as there is no need to add additional information. In fact if you were to wrap the result in a tuple, then you can't easily chain calls together e.g. foo(bar(N)) may not work if bar/1 returns {ok, _}. Good examples are: lists:nth/2 and math:cos/1.
  • If the function has only a success case without a meaningful result, the common idiom is to return ok or true as opposed to whatever the last returned value in the function happened to be. Good examples are: ets:delete/1 and io:format/1.
David Weldon
  • 63,632
  • 11
  • 148
  • 146
  • 5
    An addition I'd like to make is that you should only return `{error, Reason}` if it is meaningful for the user to be able to handle the error. If it is an unrecoverable error, it is better thrown as an exception. – Adam Lindberg Jul 26 '11 at 07:33
  • `lists:nth/1` is not such a good example, because it _does_ have a failure case (which the user should be able to handle). – Alexey Romanov Jul 26 '11 at 07:49
  • 1
    This is a valid example because `lists:nth/2` will fail only if it's given invalid input. `math:cos(foo)` will fail in the same way. Both are unrecoverable, and therefore throw an exception. The pattern, as I described it, refers only to recoverable errors (see Adam's comment). – David Weldon Jul 26 '11 at 18:58
6

Suppose my function returns an integer N. Should my function return just N, or {ok, N}?

If there is no possibility of error at all, or any error indicates a programming error, N. If there may be a good reason to fail, return {ok, N} (and {error, Reason} in case of failure).

Should it return ok or nothing at all?

In Erlang, you can't return nothing at all. If you don't have a meaningful return value, ok will do fine.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
2

This is a conundrum I find myself in many atimes. The rule of the thumb (atleast my thumb) is that if a function is to be used primarily with other functions (higher order functions like map(), filter() etc..) or if the function is designed to be "purely" functional (no side effects), then I would prefer to NOT return an {ok, _} and simply return the result. Errors in this case must be due to some logical/algorithmic error which should be fixed and the client of the function should be made aware of any such error.

arun_suresh
  • 2,875
  • 20
  • 20
  • Perhaps the answer could be expanded a bit further -- I like the direction you are going and think I understand what you are getting at, but perhaps a bit more work needs to go into it to express to newcomers what you mean. Maybe provide a logical condition like: "if the function is *composable* and *pure* -> don't return `ok`; else it should always return `ok` or `{ok, Result}`", and maybe illustrate that in code. In any case, this is indeed a useful concept in many cases. – zxq9 Jun 12 '15 at 05:23