loop exit question

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

loop exit question

Willem Broekema
If a function should loop forever while remembering some
state, most examples I have seen use:

loop(State) ->
   receive
       stop ->
           stopped_upon_request;
       Other ->
           ...,
           loop(State)
   end.

Now, if the State is not changed in any of the 'reveiced'
branches, is there a reason not to move the final 'loop()'
command to the end, and use 'exit()' for breaking out of
the loop, like in the following?

loop2(State) ->
   receive
       stop ->
           exit(self(), stopped_upon_request);
       Other ->
           ...
   end,
   loop(State).


TIA

- Willem



Reply | Threaded
Open this post in threaded view
|

loop exit question

Claes Wikström
On Thu, Apr 19, 2001 at 02:02:43PM +0200, Willem Broekema wrote:

> If a function should loop forever while remembering some
> state, most examples I have seen use:
>
> loop(State) ->
>    receive
>        stop ->
>            stopped_upon_request;
>        Other ->
>            ...,
>            loop(State)
>    end.
>
> Now, if the State is not changed in any of the 'reveiced'
> branches, is there a reason not to move the final 'loop()'
> command to the end, and use 'exit()' for breaking out of
> the loop, like in the following?
>
> loop2(State) ->
>    receive
>        stop ->
>            exit(self(), stopped_upon_request);
>        Other ->
>            ...
>    end,
>    loop(State).
>
>


No, that's the way to do it.


/klacke


--
Claes Wikstrom                        -- Caps lock is nowhere and
Alteon WebSystems                     -- everything is under control          
http://www.bluetail.com/~klacke       --



Reply | Threaded
Open this post in threaded view
|

loop exit question

Gunilla Arendt-3
Klacke wrote:

>
> On Thu, Apr 19, 2001 at 02:02:43PM +0200, Willem Broekema wrote:
> > If a function should loop forever while remembering some
> > state, most examples I have seen use:
> >
> > loop(State) ->
> >    receive
> >        stop ->
> >            stopped_upon_request;
> >        Other ->
> >            ...,
> >            loop(State)
> >    end.
> >
> > Now, if the State is not changed in any of the 'reveiced'
> > branches, is there a reason not to move the final 'loop()'
> > command to the end, and use 'exit()' for breaking out of
> > the loop, like in the following?
> >
> > loop2(State) ->
> >    receive
> >        stop ->
> >            exit(self(), stopped_upon_request);
> >        Other ->
> >            ...
> >    end,
> >    loop(State).
> >
> >
>
> No, that's the way to do it.
>

I disagree. You might be saved the effort of having to type
"loop(State)"  more than once, but you lose readability
and maintainability. I can't count the number of times I have
debugged code behaving strangely and found constructs like this:

loop(State) ->
  stop ->
    exit(stop);
  ...
  Pattern ->
    ...,
    loop(State);
  ...
  Other ->
     ignore
  end,
  loop(State).

/ Gunilla


Reply | Threaded
Open this post in threaded view
|

loop exit question

Robert Virding-4
In reply to this post by Willem Broekema
Willem Broekema <willem> writes:

> ...
>Now, if the State is not changed in any of the 'reveiced'
>branches, is there a reason not to move the final 'loop()'
>command to the end, and use 'exit()' for breaking out of
>the loop, like in the following?
>
>loop2(State) ->
>   receive
>       stop ->
>           exit(self(), stopped_upon_request);
>       Other ->
>           ...
>   end,
>   loop(State).

NOTE!!!!  Exit/2 sends an exit signal to a process, so
exit(self(),xxx) sends an exit signal to itself.  This is *NOT* the
same as calling exit(xxx)!!!

The exit/2 signal can be trapped while exit/1 cannot, while exit/1 can
be caught (in a catch) while exit/2 signals cannot.  You have to be
careful to choose the "right" one.

This difference is intentional.

        Robert


Reply | Threaded
Open this post in threaded view
|

loop exit question

Ulf Wiger-4
In reply to this post by Willem Broekema
On Thu, 19 Apr 2001, Willem Broekema wrote:

>Now, if the State is not changed in any of the 'reveiced'
>branches, is there a reason not to move the final 'loop()'
>command to the end, and use 'exit()' for breaking out of
>the loop, like in the following?
>
>loop2(State) ->
>   receive
>       stop ->
>           exit(self(), stopped_upon_request);
>       Other ->
>           ...
>   end,
>   loop(State).

How you want to terminate your process depends in part on how you're
implementing it (plain erlang, gen_server, 'sys' compliant plain
erlang, ...), and in part on the context in which it is executing.

I would write the loop like this:

loop2(State) ->
   receive
      stop ->
         terminate(normal, State);
      Other ->
         NewState = handle_message(Other, State),
         loop2(NewState)
   end.

terminate(Reason, State) ->
   exit(Reason).   %% note: exit/1

handle_message(Msg, State) ->
   ...



I will give a few examples of context issues to consider:

- if you're using SASL, and the process was started with e.g.
  proc_lib:spawn_link/3 (as it should), exit(stopped_upon_request)
  would be interpreted as an abnormal exit, and would lead to a
  crash report. exit(normal) would not.

- If the process is supervised, and is started as a transient
  process, any exit reason other than normal would cause the
  supervisor to restart the process.

- If the process is supervised and trapping EXITs, it would
  have to trap the following message:

   receive
      {'EXIT', Parent, shutdown} ->   %% assume Parent is bound
         terminate(shutdown, State);
      ...
   end.


This in order to comply with the OTP shutdown protocol.

Of course, if you use an OTP behaviour, like gen_server, you get
much of this for free.


/Uffe
--
Ulf Wiger                                    tfn: +46  8 719 81 95
Senior System Architect                      mob: +46 70 519 81 95
Strategic Product & System Management    ATM Multiservice Networks
Data Backbone & Optical Services Division      Ericsson Telecom AB