[erlang-questions] Why doesn't Erlang has return statement?

Gilberio Carmenates Garcia co7eb@REDACTED
Wed Dec 17 16:07:12 CET 2014


Hi everyone, I like Erlang without a return statement, it is more clean and beautiful, despite, the fact that you can elegantly treat a return case the same as a non-return case by simply returning always whatever you want of implicit manner. 

it is not the same writing:

return pass or none.
than just pass or none

foo()->
    pass;
foo(1) ->
    return (pass);  // weird right ?
foo(X)->
    X * 2;

in Erlang all methods are functions so they obligatory have to always return, being implicit or explicit they always need to return something. Because if not, you break the standards rules of functional programming. and make a nasty mix of paradigms.


Regards,
Ivan.

 


----- Mensaje original -----
De: Joe Armstrong <erlang@REDACTED>
Para: Viktor Söderqvist <viktor@REDACTED>
CC: Erlang <erlang-questions@REDACTED>
Enviado: Wed, 17 Dec 2014 04:20:15 -0500 (CST)
Asunto: Re: [erlang-questions] Why doesn't Erlang has return statement?

The question was : Why doesn't Erlang have a return statement

I can let you into a secret - the first version of Erlang *did* have a
return statement

return was written ^Expression.

Something like:

foo() ->
    a,b,^c.

Erlang with a return statement would look something like:

foo() ->
   a,
   b,
   return(c).

Here's some little fragments of code with returns

foo(X) ->
   case g(X) of
      pattern1 ->
           a(), b, return(c);
      pattern2 ->
          do,de,dar, return(z)
   end.

Now what would happen if all the branches in the case clause didn't
do a return?

We could write:

foo(X) ->
   case g(X) of
      pattern1 ->
           a(), b, return(c);
      pattern2 ->
          do,de,dar, return(z);
      pattern3 ->
          Y = h(H), P = z(Y)
   end,
   foo(),
   return(P).

Which kind of sucks - case is now NOT a function with a return value
it's something that either returns a value OR binds some variables
whose values escape from the case construction. In this case
P escapes so we can use it after the case construct.

This is a bit messy so we might rewrite it like this

foo(X) ->
   P =  case g(X) of
           pattern1 ->
             a(), b, return(c);
           pattern2 ->
             do,de,dar, return(z);
           pattern3 ->
             Y = h(H), z(Y)
   end,
   foo(),
   return(P).

Again case is "funny" - from a flow of control point of view it can
either a) return to the caller or b) carry on executing *after* the
end statement.

This actually makes it difficult to understand. It's really easy to
"see" this in the small example above - but if the case statement had
dozens of branches and one of them had a return in and all the others
didn't this would be very difficult to spot.

Now there are actually two methods for making an abrupt return
from a function - exit(Expr) and throw(Expr).

Both are in a sense "returns" (note the quotes).

exit is for an abnormal return - throw is used to break out of
computation, ie to return a value to some grand parent of the called
function.

In the absence of return(X) you can write throw(X) but this
can make your programs more difficult to understand if abused.

Cheers

/Joe

On Tue, Dec 16, 2014 at 11:58 PM, Viktor Söderqvist
<viktor@REDACTED> wrote:
> On 2014-12-16 09.05, aman mangal wrote:
>
> Moreover, is there a good alternate to avoid nested case statements?
>
> One way is to avoid them is actually not to write them. Especially if the
> cases are error handling, handle only the expected case and let everything
> else crash.
>
> When I'm parsing some input or structure and want to return {ok, Value} or
> 'error' instead of crashing, I often wrap that code in a try-catch. This is
> only when dealing with untrusted input and similar situations.
>
> parse_foo_url(URL) ->
>     case http_uri:parse(URL) of
>         {ok, {_, _, _, _, Path, _}} ->
>             case re:split(Path, "/", [{return, list}]) of
>                 ["", "foo", Foo] ->
>                     try list_to_integer(Foo) of
>                         FooInt -> {ok, FooInt}
>                     catch error:_ ->
>                         error
>                     end;
>                 _BadPath ->
>                     error
>             end;
>         _BadUri ->
>             error;
>     end.
>
> ---->
>
> parse_foo_url(URL) ->
>     try
>         {ok, {_, _, _, _, Path, _}} = http_uri:parse(URL),
>         ["", "foo", Foo] = re:split(Path, "/", [{return, list}]),
>         FooInt = list_to_integer(Foo),
>         {ok, FooInt}
>     catch error:_ ->
>         error
>     end.
>
> Using catch statement seems another good alternate but my intuition is that
> it is not good practice, is it?
>
> In the above example I dare to say it's not bad practice. Just don't overuse
> try-catch so that it becomes defensive programming and make sure you don't
> put any other code inside the try-catch so that you accidentally catch
> totally unrelated errors.
>
> Viktor
>
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions
>
_______________________________________________
erlang-questions mailing list
erlang-questions@REDACTED
http://erlang.org/mailman/listinfo/erlang-questions




More information about the erlang-questions mailing list