On 23 August 2017 at 11:20, Bakul Shah <[email protected]> wrote:
> On Wed, 23 Aug 2017 09:48:14 BST roger peppe <[email protected]> wrote:
>> On 23 August 2017 at 09:40, roger peppe <[email protected]> wrote:
>> > On 23 August 2017 at 09:23, MartinG <[email protected]> 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 [email protected].
For more options, visit https://groups.google.com/d/optout.