On 23 August 2017 at 11:20, Bakul Shah <ba...@bitblocks.com> wrote: > On Wed, 23 Aug 2017 09:48:14 BST roger peppe <rogpe...@gmail.com> wrote: >> On 23 August 2017 at 09:40, roger peppe <rogpe...@gmail.com> wrote: >> > On 23 August 2017 at 09:23, MartinG <gar...@gmail.com> wrote: >> >> Thanks for the fantastic explanation folks. >> >> >> >> I wonder if I can ask advice on how to improve my use case. I have a stru >> ct >> >> type that represents a state machine and each state is handled by a >> >> different method on that type, each with the same signature I use a >> >> function variable to represent the current state and it is simply set to >> >> point at one of the methods. The state is modified frequently, hence my >> >> problem. >> >> >> >> The options I can think of are: >> >> >> >> 1) Define another type (probably based on int or similar) representing the >> >> current state and switch on that instead of using a function type. This >> >> feels inelegant and avoids using function types on one of the scenarios th >> ey >> >> seem to be designed for. >> >> 2) Define non-method related functions with a similar signature, but that >> >> also take my base type as an additional parameter. I believe this will >> >> avoid the allocation, but also feels wrong because these functions really >> >> "belong" to my base type so should be methods. >> >> >> >> Any other possibilities? >> > >> > You could use method expressions. >> > >> > For example: >> > >> > https://play.golang.org/p/9H1n-CevNJ >> >> Actually, it occurs to me that using method expressions in this way is >> actually more powerful, because the state can be manipulated independently >> of the state transitions. You could use this, for example, to fork the >> state machine and run it concurrently from an arbitrary state. > > I find regular functions much cleaner (and a closer analog of > a digital FSM). See for example: > > https://play.golang.org/p/MpX_lNT4rS > > Basically > > type state func(inputType) state > > func reset() { return initial } > > func initial(i inputType) state { > if needChange(i) { return stateOne } > return initial > } > > func stateOne(i inputType) state { > // etc. etc. > }
As we know, this really isn't far removed from: func (i inputType) stateOne() state The only difference is that by defining it as a method, we're making the association a little closer, and that using a method forces you to mention the type name to get a handle on the method (presumably that's the "boilerplate" you're talking about?) Which is nicer is just a matter of taste then, I think. In a larger package, the namespacing might be quite nice - it means you could easily have two or more FSMs with different input types but similar state transition names without needing disambiguation for your transition function names. > > func main() { > s := reset() > for s != nil { > s := s(readInput()) > } > } > > and so on. This is a Mealy machine, where the next state > depends on the current state and current input (in s/w not > much use for a Moore machine unless you are driving/simulating > some regular physical process, in which case you don't need > any input parameter). If you want a side effecting FSM, pass > in a ptr to some mutable state. > > Since these are essentially pure functions you can run them in > parallel. I tend to think use of methods requires more > boilerplate and is more obfuscating. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.