<div dir="ltr"><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">I usually stuff the events into a map and then have a handle_continue/2 like behavior to check if everything in the map is present.</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">Simplified:</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">event(a, State) -></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">    check(State#{ a => true });</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">event(b, State) -></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">    check(State#{ b => true });</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">...</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">check(#{ a := A, b := B} = State) -></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">    end(A, B, State);</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">check(#{} = State) -></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">    {noreply, ...}.</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">Usually, rather than storing true, I'd store the event data there, and rather than having a map() at the top-level I'd probably have a record. But the gist of the idea is there. A more advanced variant of this will have a defined state machine and valid transitions between them. Then check is also an invariant on the transitions validity and it becomes a (runtime) contract to check against.</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">Aside: Idris can do this check at compile time, but since we don't have dependent types...</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div></div><br><div class="gmail_quote"><div dir="ltr">On Sat, Jun 23, 2018 at 9:07 AM Oliver Korpilla <<a href="mailto:Oliver.Korpilla@gmx.de">Oliver.Korpilla@gmx.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello.<br>
<br>
In the system we're building we're using gen_statem processes to keep track of signalling scenarios, essentially series of different types of messages from various sources. For linear or branching scenarios gen_statem is well prepared. But there's one thing that seemed to be missing and that is support for joins?<br>
<br>
I recently reviewed a developer's code that implemented receiving two different messages that could arrive in any order as four state functions - receiving A first (1), then receiving B (2), then entering an end state; or receiving B first (3), then receiving A (4), then entering an end state. The code entering the end state was duplicated in both (2) and (4). What essentially was needed was a "check list" of which messages had already arrived to determine the transition into the end state.<br>
<br>
Such "check list" scenarios are quite common in our work (and can grow to be more complex) and I couldn't find a direct support for it (though I was limiting myself to state_function mode), so we're now starting a separate "join process" - a gen_server that keeps and maintain the join list - and do the decision now from a single wait state. Given how light-weight Erlang processes are this works fine.<br>
<br>
What prevented me from doing this through data maintained between calls was that I would have to partition the state into information for tracking the join and the actual information kept to process the signals. This seemed less generic and clean.<br>
<br>
I'm also aware that had I rewritten the whole state machine to handle_event functions and utilized a complex state this could have helped achieve the same. What is essentially is needed, from my POV, is a way to track information pertaining to state transitions separate from information for processing incoming events, and complex states seem to do that...?<br>
<br>
What is your preferred way of doing this? Is it possible to somehow support this at the library level? Are handle_event/complex states the way to go in such situations?<br>
<br>
Thank you and regards,<br>
Oliver<br>
_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" rel="noreferrer" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">J.</div>