4

To make the question short, what is the reason why there is no return statement in Elixir and some (most ? all ?) functional languages ?

To make it a bit longer, I'm facing a situation where in Java, Groovy, C, Ruby ... I would write some thing like

def func (some, parameters) {

  # say some error
  if(condition 1) {
    return -1
  }

  # execute some function and return from here the result
  if(condition 2) {
    return process1(params)
  }

  # execute 'default' behavior when no condition matches and return result
  process2(params)
}

Of course, this can be written as nested ifs but if the list of conditions is long, the code just gets unreadable.

I read the answers for the question Return statement in Elixir : they explain clearly how to implement this kind of pattern but not the reason of not having return.

I believe having return would break some FP concept but I wonder which ones and why.

Community
  • 1
  • 1
mszmurlo
  • 1,250
  • 1
  • 13
  • 28
  • 1
    FYI You can use `cond` instead of nested `if` in Elixir. With `cond` you won't have more than 1 extra level of indentation compared to the code you've written (that too for the last group of statements only). – Dogbert Jan 07 '17 at 09:43
  • 1
    Or you can use `with` which can be very useful in some situations and makes code readable and nice. But I am also interested why there is no built in return statement. – NoDisplayName Jan 07 '17 at 10:39
  • You're asking a pretty broad question. There's discussion of this here: http://wiki.c2.com/?SingleFunctionExitPoint among other places. I am inclined to say this should either be closed or moved to Programmer's Stack Exchange. – Onorio Catenacci Jan 07 '17 at 21:55

2 Answers2

5

Because there are other ways to do that same thing that is more like Elixir.

Multiple function heads do basically the same thing as what you're doing:

defp merge_sweep(a, [], _) when is_list(a), do: a
defp merge_sweep([], b, _) when is_list(b), do: b
defp merge_sweep([a|as], [b|bs], cmp) do
  if cmp.(a, b) do
    [a|merge_sweep(as, [b|bs], cmp)]
  else
    [b|merge_sweep([a|as], bs, cmp)]
  end
end

And since functions in functional programming don't have any side-effects (ignoring :ets for now), why should you have to write return everywhere? You always want to return something in every branch, so you might as well just always return the last expression in each branch.

I asked for Golang's defer statement in Elixir when I started, because I came from Go. It's simply that each language has a different way of doing things. Writing C-like code in Python just looks weird and foreign.


The real answer is probably "because Erlang doesn't".

Filip Haglund
  • 13,919
  • 13
  • 64
  • 113
1

The short answer is because Erlang doesn't have early returns.

The longer answer is because early returns are an anti-pattern and they make your code harder to read and reason about. It doesn't have anything to do with functional programming other than it being a common feature of "functional" programming languages. There is no program you can write with early returns that you can't without them.

greg
  • 102
  • 3
  • 3
    This answer seems dogmatic to me. Opinions on readability will vary, but the original question was seeking to avoid the nested `if` to be more readable. Guard clauses are more idiomatic and I think more readable. (Filip's answer is closer to the mark for me.) – cleaver Jan 09 '17 at 07:41
  • @cleaver programming languages are very dogmatic – greg Jan 11 '17 at 14:51