[erlang-questions] gen_fsm + handle_info = spaghetti code?

Janos Hary <>
Mon Aug 5 22:41:44 CEST 2013


Thanks for all the suggestions. I tried Fred's cheating solutions and its
working for me very well (after I figured the missing $ sign in
'$gen_event', but at least I had to look up the gen_fsm source). 
I'd be interested in the alternative implementation, especially if you could
show those half of the cases where the library version gets annoying.

Thanks again,
Janos

-----Original Message-----
From: Jachym Holecek [mailto:] 
Sent: Monday, August 05, 2013 8:33 PM
To: Fred Hebert
Cc: Janos Hary; 
Subject: Re: [erlang-questions] gen_fsm + handle_info = spaghetti code?

# Fred Hebert 2013-08-05:
> I would consider having a middle-man process whose role is to deal 
> with the NIF code, and turns messages received into gen_fsm events.

Notice that the return convention of handle_info/3 and State_name/2 is the
same, so you can just do:

  handle_info(Info, State_name, State_data) ->
      ?MODULE:State_name(Info, State_data);

No middleman process needed, and you still get your full-on state machine.

That said, I find gen_fsm's event wrapping habit annoying in maybe half of
the cases where I do want a FSM, so I wrote a 'fsm' behaviour which is very
close to gen_fsm but avoids the wrapping. Can publish that after a little
bit of polishing if there's interest (it has some other extra niceties, but
nothing major).

BTW you'll sometimes see people doing this to "solve" the same problem:

  handle_info(Info, State_name, State_data) ->
      gen_fsm:send_event(self(), Info);

Which is obviously incredibly broken -- for one it reorders messages and for
other it does so unpredictably!

> Alternatively, the NIF could cheat and use the internal gen_fsm 
> wrapping of messages ({'gen_event', Event}, where Event is the original
message).
> the gen_fsm process will receive that message and think of it as if it 
> were sent as an asynchronous event through the regular gen_fsm 
> functions, and call your own custom states.
> 
> This is a bit messier given you break the abstraction, but should be 
> faster at run time than having a middle-man just forward stuff.

That strikes me as a clean approach also: it solves the problem in a very
simple and straightforward way, it doesn't introduce any undue (and, more
importantly, any realistic) risks, and the question of "breaking the abs-
traction" could be argued to be largely a matter of perception in this case
and also to be somewhat overrated in general. Overall, what's there not to
like?

[Here I'm speaking as someone who's doing gen_server:reply/2 shamelessly
from a NIF thread in one project. :-) It was the best way to get the flow
control I needed in given circumstances, abstractions broken or not...]

BR,
	-- Jachym




More information about the erlang-questions mailing list