[HN Gopher] Show HN: State Trooper - Tiny, no frills state machi...
       ___________________________________________________________________
        
       Show HN: State Trooper - Tiny, no frills state machine for Go
        
       Needed to isolate a bit of DRY logic for some of my projects. Might
       be of use to others out there.
        
       Author : hishamk
       Score  : 76 points
       Date   : 2023-06-17 14:21 UTC (8 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | naikrovek wrote:
       | I am actually angry at how good the project name is.
        
         | jnordwick wrote:
         | I've written 2 in C++ for different projects at companies State
         | Farm and State of Decay. I'm trying to write one that kind of
         | inverts things and calling it Enemy of the State.
         | 
         | But yes, his name pisses me off because I didnt think of it
         | either.
        
       | easeout wrote:
       | May I suggest for a logo: A directed graph in the form of a
       | sheriff's star badge
        
         | icyfox wrote:
         | Midjourney actually does pretty well with this one (needs a bit
         | of cleanup but shockingly useful as a first draft):
         | https://imgur.com/a/GKzx3vX
        
           | hishamk wrote:
           | Ha! Not bad at all.
        
       | [deleted]
        
       | klabb3 wrote:
       | I saw the benchmark which seemed crazy (3us per transition and
       | allocations). So looked quickly at the code.
       | 
       | Recommend putting the tracking of previous states in a separate
       | optional debugging type so you don't have to pay the cost in
       | general. Oh and using time stamps as a key is kinda weird, but
       | even weirder in Go where maps are non-deterministically
       | enumerable.
       | 
       | Otherwise, seems like a good use of generics, given Golangs
       | particular take on it.
        
       | victorbjorklund wrote:
       | Great name!
        
         | hishamk wrote:
         | Thank you!
        
       | earthboundkid wrote:
       | A state machine should have more than states. It also needs
       | _actions_ which cause transitions. The API should be about
       | writing out which new state an action causes given a base state.
       | Eg you have a modal with a button and it can be clicked or
       | dismissed. In the open state, click and dismiss cause close, and
       | in the closed state, click causes open. Anyway, the whole thing
       | is only valuable once you have actions.
        
         | packetslave wrote:
         | Commenters like you are why people don't share thing. Why make
         | something available _for free_ when someone like you is just
         | going to come along and shit on it?
        
           | akira2501 wrote:
           | If your only reasoning behind releasing an open source
           | project is to receive uncritical accolades just for producing
           | open source, then I think you need to examine your motives
           | and seriously question why you expected this deference in the
           | first place.
        
           | [deleted]
        
           | jawr wrote:
           | Commenters like you are why people don't give honest
           | feedback. Why review something for free when someone like you
           | is unable to accept honest feedback even if it is critical.
        
         | BSEdlMMldESB wrote:
         | you mean like:
         | 
         | > Add valid transitions between states:
         | 
         | > `fsm.AddRule(CustomStateEnumA, CustomStateEnumB)`
         | 
         | > `fsm.AddRule(CustomStateEnumB, CustomStateEnumC)`
        
           | Someone wrote:
           | I don't like that name.
           | 
           | IMO, _AddValidTransition_ would be way better. I think I
           | would go for _AddTransition_ , though. It's not as if there's
           | also a way to add invalid transitions.
        
           | infogulch wrote:
           | They should be named and other transitions disallowed.
        
       | bsaul wrote:
       | enums with associated values (like in swift) really are the thing
       | i miss the most in go.
        
         | pjmlp wrote:
         | Yeah, yet another Algol 60 missing feature.
         | 
         | I really don't get how one can suggest the iota const dance
         | with a straight face as an alternative.
        
           | rochak wrote:
           | The sooner you realise Go is just C with some niceties, the
           | better.
        
             | pjmlp wrote:
             | When are C enumerations coming to Go?
        
       | pokstad wrote:
       | Looks cool. It'd be nice if you could output the FSM to some kind
       | of diagram markup (plantuml or mermaidjs).
        
       | syngrog66 wrote:
       | A state machine (specifically a FSM) class is something I end up
       | having to reinvent in every new language I've adopted. Such a
       | useful pattern whose need comes up repeatedly. Especially in
       | games/sims or in anything with a GUI. Since I've been making both
       | for decades I have a lot of homegrown FSM classes sitting around.
       | :-p
        
         | samsquire wrote:
         | I am working on a state machine formulation/notation that can
         | be executed.
         | 
         | The runtime is multithreaded and parallel.
         | 
         | The idea is to execute the following state machine:
         | thread(s) = fact(variable) | send(message) | receive(message2);
         | thread(r) = fact(variable) | receive(message) | send(message2);
         | 
         | This program waits until thread(s) is true in another thread
         | until thread(r) is true, everything left of the equals symbol
         | needs to be true before it passes to the next group of facts
         | after the = symbol. Then it waits for "fact(variable)" to be
         | fired, then when all those atoms are true, the state
         | transitions past the pipe symbol and does a send(message) while
         | the other thread does a receive(message) and then the process
         | is repeated in the opposite direction. I've not shown it here,
         | but you can wait for multiple facts to be true too.
         | 
         | Here's a state machine for an (echo) server that is intended to
         | be mapped to epoll or libiouring:                  accept | {
         | submit_recv! | recv | submit_send } { submit_send! | send |
         | submit_recv }
         | 
         | The curly brackets means parallel state machines that run
         | independently, like a fork.
        
           | syngrog66 wrote:
           | love it! shutup and take my money/adoption/usage/attention!
           | ha
           | 
           | no but seriously, sounds like a good/useful plan/approach.
           | please let me know if you share out a spec or impl sometime
           | 
           | BONUS points for a Golang or C lib
        
           | syntheweave wrote:
           | That is a description of flow-based programming, minus the
           | generalization to "arbitrary packets of data in bounded
           | buffers" - that is, your only data type is true/false and
           | your only buffer size is 1, which lets you get some very
           | clean syntax on it. It's a good invention!
           | 
           | FBP adapts the physical concept of unit record machines that
           | operate over punchcard stacks, which predisposes it to
           | thinking in terms of processing and transforming richer data
           | like "characters in a string" or "records in an array", but
           | it basically works for truth-signalling logic too - let truth
           | packets wait in a buffer, and then when the node signals that
           | the packets are able to move, that is the transition.
           | 
           | The emphasis does differ in that if we are thinking "FSM",
           | the rest of the program and the data it handles have been
           | abstracted, while if we are thinking "FBP" we're engaged with
           | designing specific machines to connect together in terms of
           | I/O, which is more helpful when you have a library of data
           | operations to reuse.
        
       | whywouldudothat wrote:
       | [dead]
        
       | preseinger wrote:
       | func (fsm *FSM[T]) Transition(...) {           ...
       | fsm.Transitions[time.Now()] = Transition[T]{
       | FromState: *fsm.CurrentState,            ToState:   targetState,
       | Timestamp: &tn,            Metadata:  metadata,           }
       | 
       | does fsm.Transitions grow without bounds?
        
       | wahnfrieden wrote:
       | [flagged]
        
         | Solvency wrote:
         | Rust - A memory safe programming language
         | 
         | wahnfrieden: Why the iron oxide name? Besides the fact that
         | it's a pun. Is the code written with it always bound to be
         | rusty and old?
        
           | wahnfrieden wrote:
           | [flagged]
        
       | MobileVet wrote:
       | Nice work!! I have always appreciated the clarity of FSMs since
       | first learning about them in college. They are a great way to
       | think about a system's state and given X input, clearly define
       | the next state. This makes them very easy to test as well.
        
       | giraffe_lady wrote:
       | [flagged]
        
         | brigadier132 wrote:
         | This would be hilarious if it was satire
        
           | giraffe_lady wrote:
           | [flagged]
        
             | Anon_Forever wrote:
             | [flagged]
        
             | [deleted]
        
         | oofta-boofta wrote:
         | Tell me your a DEI Director without actually telling me you're
         | a DEI Director.
        
           | giraffe_lady wrote:
           | Nah just a guy who had some teeth knocked out by the state
           | police.
        
       | jupp0r wrote:
       | Nice job. In my own usage of state machine libraries over the
       | years I have found that for complex use cases, it's definitely
       | helpful to have event-based transition dispatching be part of the
       | library. The great benefit of FSMs is that you can express in
       | data a lot of aspects that you would normally express in code.
       | Not knowing what event needs to happen to transition to one state
       | vs another leaves out a lot of the benefits that you get from
       | designing your code around FSMs.
       | 
       | That being said, I appreciate the simplicity and it's a totally
       | fine choice to leave out event based dispatch for less complex
       | use cases!
       | 
       | One thing that has been mentioned here already: it's super
       | helpful to have your library output a diagram file to visualize
       | the FSM. This is a really great way to keep code and
       | documentation in sync always.
        
         | hishamk wrote:
         | Thank you. The focus was on simplicity and handling less
         | complex scenarios. In my current projects the business logic
         | lends itself to sitting outside the FSM/State Trooper. The
         | logic dictates the transitions at arms length to the FSM. The
         | FSM does not carry on any particular business logic, it just
         | enforces the transition rules from one state to any number of
         | possible states - hence why I've included the metadata aspect
         | to embed info about the reason for a transition.
         | 
         | Re the visualization, I think that would be cool. I might give
         | that a shot.
        
       | rowls66 wrote:
       | Interesting. I wrote almost the same code for work a couple of
       | weeks ago.
       | 
       | Not sore, but it looks like the Transition function has a race
       | condition. It calls CanTansition() before acquiring the mutex
       | lock. I think this could lead to illegal state transitions.
        
         | hishamk wrote:
         | Thanks for this. You are indeed correct. I've pushed a fix and
         | also added a race test to confirm the fix.
        
       ___________________________________________________________________
       (page generated 2023-06-17 23:01 UTC)