[erlang-questions] gen_statem state enter call and changing t oanother state

Frans Schneider fchschneider@REDACTED
Mon Jun 11 13:07:31 CEST 2018

Thanks Raimo,

See your point, but I am not yet really convinced.
Using a helper function would in my case.opinion  make the code more 
obliterative. I think the following code makes it very clear what goes 
on while some helper function called from whatever other place would 
make things much more obscure.

	     #state{reliability_level = reliable,
	            state1 = announcing} = State,
	     #data{changes = []} = Data) ->
     {next_state, State#state{state1 = idle}, Data};
	     #state{reliability_level = reliable,
	            state1 = announcing},
	     #data{push_mode = true} = Data ->
     {next_state, State#state{state1 = pushing}, Data};
	     #state{reliability_level = reliable,
	            state1 = announcing},
	     #data{push_mode = false,
	           heartbeat_period = Heartbeat_period} = Data) ->
     Hb_timer_ref = erlang:start_timer(Heartbeat_period, self(), hb),
     {keep_state, Data#data{heartbeat_timer_ref = Hb_timer_ref}};

Currently, I resort to testing for a particular condition in the state 
enter code and insert a next event (changes_not_empty) to trigger the 
state change I need, which however also introduces extra code and makes 
things also less obvious.

Also, your co-locating argument is arguable since when using complex 
states and handle_events, I tend to use a different ordering of the 
functions, mostly focusing on the type of events to handle. (I know, 
'enter' isn't an event of course.)


On 06/11/2018 10:45 AM, Raimo Niskanen wrote:
> On Mon, Jun 11, 2018 at 09:43:02AM +0200, Frans Schneider wrote:
>> Dear list,
>> the state_enter_result(State) has as one its return values {next_state,
>> State, NewData, ...} but explicitly disallows the State to be different
>> from the current State,  First, I find it confusing to allow
>> 'next_state' here since State cannot change but the name makes the
> Throughout gen_statem is is by design so that there is no difference
> between {next_state, SameState, NewData, ...}
> and {keep_state, NewData, ...}.  It is {keep_state, ...} that is shorthand
> for {next_state, SameState, ...}.
> So dissalowing {next_state, ...} in a state_enter call would be an
> exception to the main rule that {next_state, ...} is the generic form.
> There might be situations where you have a helper function that calculates
> the next state so it would want to always return {next_state, ...}, and
> then you want to use it in a state_enter call context knowing it will
> always return {next_state, SameState, ...}.  I think this use should be
> possible.
>> suggestion it can. Secondly, I would love to be able to actually make a
>> state change. Quite often i find myself running a few tests on entering
>> a state and making state changes based on these tests. Now I have to
> The state_enter call is intended for code to be executed when entering a
> state, making this code co-located in the source with the state's event
> handling code.
> If the state_enter call should be allowed to change states it would no
> longer be co-located since it would for example start a timer for the other
> state it changes to.
> The alternative to using state_enter calls would be to have a convention
> where you at exit from the other state go through a helper function
> that does what you need for state entry, and remember to use this
> function for every state entry to the state in question.
> I think your use case is a good example for when having a specialized state
> change function makes sense.  There is no single state this kind of code
> clearly should be co-located with.
>> move these tests to all states which can have this state as a result and
>> go directly to the end state.
>> Would it be possible to change state from a state enter call?
> I do not like that idea, for the reasons above...
>> Frans

More information about the erlang-questions mailing list