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.

Reply via email to