FAQ
Hello,

the subject is not very clear but I found it difficult to summarize.

I've been playing with the idiom for a state machine proposed a couple
of years ago by nsf here: https://groups.google.com/d/msg/golang-nuts/P8Xs8Dgeo4Q/yaRP2nVlPeYJ

I wrote some code and I got to the point where I wanted to write a
"generic" method I could call on any state.

I found a (for me) unexplicable behaviour. I have some vague ideas about
what I'm doing wrong but I don't know Go well enough to have a good
explanation.

Here is the shortest code I managed to put together which generates the
problem: http://play.golang.org/p/eGxko5YkLu

What I get when I call a.funcTwo() on line 25 is as infinite loop of
calls of the function defined at lines 12-14 (at least, this is what I
see in a stack trace killing -ABRT the process before it eats all my
ram).

If I cast a to (*A) (line 24), the call works fine; same if I define a
new method on the interface AFoo (commented out lines 16-18).

I guess that what I'm trying to do (call a method defined on *A on an
*AFoo) is "somehow" wrong, but I cannot find the exact reason.

(the assignment at line 30 is part of nsf's idea for the state machine;
what would normally happen is that a.B is replaced at each state
transition with a cast of "a" to the type corresponding to the new
state, so a loop of calls to a.funcOne() would make the state machine
work)

Thank to anyone who will enlighten me :-)

Ludovico
--
<lu@dovi.co> IRC: garden@freenode
OpenPGP: 1024D/63D2D5D907F89BB8 Jabber/gtalk: gardengl@gmail.com

--

Search Discussions

  • Gordon Klaus at Jan 17, 2013 at 11:42 pm
    That's an interesting kind of unbounded recursion. It seems to be stuck in
    a method lookup loop. You see, AFoo doesn't inherit any methods that were
    explicitly defined on A, but it does inherit those that A gained by
    embedding B (it's a funny trick whose reason and use I don't understand).
    Thus, a call to AFoo.funcTwo() is forwarded to A.B.funcTwo(); and because
    your particular A.B is the original AFoo, this repeats unboundedly.
    However, I don't understand why the debugger would point at A.funcTwo().
    On Thursday, January 17, 2013 6:12:18 PM UTC-5, garden wrote:

    Hello,

    the subject is not very clear but I found it difficult to summarize.

    I've been playing with the idiom for a state machine proposed a couple
    of years ago by nsf here:
    https://groups.google.com/d/msg/golang-nuts/P8Xs8Dgeo4Q/yaRP2nVlPeYJ

    I wrote some code and I got to the point where I wanted to write a
    "generic" method I could call on any state.

    I found a (for me) unexplicable behaviour. I have some vague ideas about
    what I'm doing wrong but I don't know Go well enough to have a good
    explanation.

    Here is the shortest code I managed to put together which generates the
    problem: http://play.golang.org/p/eGxko5YkLu

    What I get when I call a.funcTwo() on line 25 is as infinite loop of
    calls of the function defined at lines 12-14 (at least, this is what I
    see in a stack trace killing -ABRT the process before it eats all my
    ram).

    If I cast a to (*A) (line 24), the call works fine; same if I define a
    new method on the interface AFoo (commented out lines 16-18).

    I guess that what I'm trying to do (call a method defined on *A on an
    *AFoo) is "somehow" wrong, but I cannot find the exact reason.

    (the assignment at line 30 is part of nsf's idea for the state machine;
    what would normally happen is that a.B is replaced at each state
    transition with a cast of "a" to the type corresponding to the new
    state, so a loop of calls to a.funcOne() would make the state machine
    work)

    Thank to anyone who will enlighten me :-)

    Ludovico
    --
    <l...@dovi.co <javascript:>> IRC:
    garden@freenode
    OpenPGP: 1024D/63D2D5D907F89BB8 Jabber/gtalk: gard...@gmail.com<javascript:>
    --
  • Gordon Klaus at Jan 17, 2013 at 11:55 pm
    Here's a minimal example, if it makes it any clearer:
    http://play.golang.org/p/XjWnMz_MkE
    It doesn't matter if you define F() on T because F() is only ever
    referenced via U and I.
    On Thursday, January 17, 2013 6:42:21 PM UTC-5, gordon...@gmail.com wrote:

    That's an interesting kind of unbounded recursion. It seems to be stuck
    in a method lookup loop. You see, AFoo doesn't inherit any methods that
    were explicitly defined on A, but it does inherit those that A gained by
    embedding B (it's a funny trick whose reason and use I don't understand).
    Thus, a call to AFoo.funcTwo() is forwarded to A.B.funcTwo(); and because
    your particular A.B is the original AFoo, this repeats unboundedly.
    However, I don't understand why the debugger would point at A.funcTwo().
    On Thursday, January 17, 2013 6:12:18 PM UTC-5, garden wrote:

    Hello,

    the subject is not very clear but I found it difficult to summarize.

    I've been playing with the idiom for a state machine proposed a couple
    of years ago by nsf here:
    https://groups.google.com/d/msg/golang-nuts/P8Xs8Dgeo4Q/yaRP2nVlPeYJ

    I wrote some code and I got to the point where I wanted to write a
    "generic" method I could call on any state.

    I found a (for me) unexplicable behaviour. I have some vague ideas about
    what I'm doing wrong but I don't know Go well enough to have a good
    explanation.

    Here is the shortest code I managed to put together which generates the
    problem: http://play.golang.org/p/eGxko5YkLu

    What I get when I call a.funcTwo() on line 25 is as infinite loop of
    calls of the function defined at lines 12-14 (at least, this is what I
    see in a stack trace killing -ABRT the process before it eats all my
    ram).

    If I cast a to (*A) (line 24), the call works fine; same if I define a
    new method on the interface AFoo (commented out lines 16-18).

    I guess that what I'm trying to do (call a method defined on *A on an
    *AFoo) is "somehow" wrong, but I cannot find the exact reason.

    (the assignment at line 30 is part of nsf's idea for the state machine;
    what would normally happen is that a.B is replaced at each state
    transition with a cast of "a" to the type corresponding to the new
    state, so a loop of calls to a.funcOne() would make the state machine
    work)

    Thank to anyone who will enlighten me :-)

    Ludovico
    --
    <l...@dovi.co> IRC:
    garden@freenode
    OpenPGP: 1024D/63D2D5D907F89BB8 Jabber/gtalk: gard...@gmail.com
    --
  • Kevin Gillette at Jan 19, 2013 at 12:57 am
    A minimal example would be: http://play.golang.org/p/mc_1a0uvbV

    That's bizarre, but not something you should be trying to do anyway. t is
    an I? sure, because t embeds I, therefore t can be assigned anywhere I is
    allowed, such as being the value assigned to t.I.
    On Thursday, January 17, 2013 4:55:31 PM UTC-7, gordon...@gmail.com wrote:

    Here's a minimal example, if it makes it any clearer:
    http://play.golang.org/p/XjWnMz_MkE
    It doesn't matter if you define F() on T because F() is only ever
    referenced via U and I.
    On Thursday, January 17, 2013 6:42:21 PM UTC-5, gordon...@gmail.com wrote:

    That's an interesting kind of unbounded recursion. It seems to be stuck
    in a method lookup loop. You see, AFoo doesn't inherit any methods that
    were explicitly defined on A, but it does inherit those that A gained by
    embedding B (it's a funny trick whose reason and use I don't understand).
    Thus, a call to AFoo.funcTwo() is forwarded to A.B.funcTwo(); and because
    your particular A.B is the original AFoo, this repeats unboundedly.
    However, I don't understand why the debugger would point at A.funcTwo().
    On Thursday, January 17, 2013 6:12:18 PM UTC-5, garden wrote:

    Hello,

    the subject is not very clear but I found it difficult to summarize.

    I've been playing with the idiom for a state machine proposed a couple
    of years ago by nsf here:
    https://groups.google.com/d/msg/golang-nuts/P8Xs8Dgeo4Q/yaRP2nVlPeYJ

    I wrote some code and I got to the point where I wanted to write a
    "generic" method I could call on any state.

    I found a (for me) unexplicable behaviour. I have some vague ideas about
    what I'm doing wrong but I don't know Go well enough to have a good
    explanation.

    Here is the shortest code I managed to put together which generates the
    problem: http://play.golang.org/p/eGxko5YkLu

    What I get when I call a.funcTwo() on line 25 is as infinite loop of
    calls of the function defined at lines 12-14 (at least, this is what I
    see in a stack trace killing -ABRT the process before it eats all my
    ram).

    If I cast a to (*A) (line 24), the call works fine; same if I define a
    new method on the interface AFoo (commented out lines 16-18).

    I guess that what I'm trying to do (call a method defined on *A on an
    *AFoo) is "somehow" wrong, but I cannot find the exact reason.

    (the assignment at line 30 is part of nsf's idea for the state machine;
    what would normally happen is that a.B is replaced at each state
    transition with a cast of "a" to the type corresponding to the new
    state, so a loop of calls to a.funcOne() would make the state machine
    work)

    Thank to anyone who will enlighten me :-)

    Ludovico
    --
    <l...@dovi.co> IRC:
    garden@freenode
    OpenPGP: 1024D/63D2D5D907F89BB8 Jabber/gtalk: gard...@gmail.com
    --
  • Ludovico Gardenghi at Jan 18, 2013 at 12:16 am
    [reposting to gordon *and* list, hit the wrong key before]
    On Thu, Jan 17, 2013 at 15:42:21 -0800, gordon.klaus@gmail.com wrote:

    You see, AFoo doesn't inherit any methods that were explicitly defined
    on A, but it does inherit those that A gained by embedding B (it's a
    funny trick whose reason and use I don't understand).
    Thanks for the explanation (also for the part I did not quote).

    As for the reason/use: if you take a look at the post I mentioned, my
    AFoo is any one of the StateA, StateB, StateC... types defined there,
    while A is State.

    The idea is to create a new type for each state and to define for it
    the method Test declared in the StateHandler interface (embedded in the
    "base" State struct).

    By updating State.StateHandler (or A.B in my case) with a cast to the
    proper StateX interface the "state machine" can work by repeatedly
    calling s.Test().

    Ludovico
    --
    <lu@dovi.co> IRC: garden@freenode
    OpenPGP: 1024D/63D2D5D907F89BB8 Jabber/gtalk: gardengl@gmail.com

    --
  • Ludovico Gardenghi at Jan 18, 2013 at 3:15 am

    On Thu, Jan 17, 2013 at 15:42:21 -0800, gordon.klaus@gmail.com wrote:

    You see, AFoo doesn't inherit any methods that were explicitly defined
    on A, but it does inherit those that A gained by embedding B (it's a
    funny trick whose reason and use I don't understand).
    Thanks for the explanation (also for the part I did not quote).

    As for the reason/use: if you take a look at the post I mentioned, my
    AFoo is any one of the StateA, StateB, StateC... types defined there,
    while A is State.

    The idea is to create a new type for each state and to define for it
    the method Test declared in the StateHandler interface (embedded in the
    "base" State struct).

    By updating State.StateHandler (or A.B in my case) with a cast to the
    proper StateX interface the "state machine" can work by repeatedly
    calling s.Test().

    Ludovico
    --
    <lu@dovi.co> IRC: garden@freenode
    OpenPGP: 1024D/63D2D5D907F89BB8 Jabber/gtalk: gardengl@gmail.com

    --
  • Rory McGuire at Jan 18, 2013 at 9:05 am
    Have you seen Rob's talk on lexical scanning? It has a clean way of running
    a state machine using functions.
    http://cuddle.googlecode.com/hg/talk/lex.html is the slides.
    On Friday, 18 January 2013 01:58:07 UTC+2, garden wrote:

    On Thu, Jan 17, 2013 at 15:42:21 -0800, gordon...@gmail.com <javascript:>wrote:
    You see, AFoo doesn't inherit any methods that were explicitly defined
    on A, but it does inherit those that A gained by embedding B (it's a
    funny trick whose reason and use I don't understand).
    Thanks for the explanation (also for the part I did not quote).

    As for the reason/use: if you take a look at the post I mentioned, my
    AFoo is any one of the StateA, StateB, StateC... types defined there,
    while A is State.

    The idea is to create a new type for each state and to define for it
    the method Test declared in the StateHandler interface (embedded in the
    "base" State struct).

    By updating State.StateHandler (or A.B in my case) with a cast to the
    proper StateX interface the "state machine" can work by repeatedly
    calling s.Test().

    Ludovico
    --
    <l...@dovi.co <javascript:>> IRC:
    garden@freenode
    OpenPGP: 1024D/63D2D5D907F89BB8 Jabber/gtalk: gard...@gmail.com<javascript:>
    --
  • Ludovico Gardenghi at Jan 18, 2013 at 8:37 pm

    On Fri, Jan 18, 2013 at 01:05:15 -0800, Rory McGuire wrote:

    Have you seen Rob's talk on lexical scanning? It has a clean way of running
    a state machine using functions.
    http://cuddle.googlecode.com/hg/talk/lex.html is the slides.
    I'll take a look, thanks!

    Ludovico
    --
    <lu@dovi.co> IRC: garden@freenode
    OpenPGP: 1024D/63D2D5D907F89BB8 Jabber/gtalk: gardengl@gmail.com

    --
  • Rob Pike at Jan 17, 2013 at 11:42 pm
    Lovely example. That is, ugh.

    Here's your funcOne. i have renamed the receiver for clarity.

    func (afoo *AFoo) funcOne() {
    println("funcOne on AFoo")
    (*A)(afoo).funcTwo() // OK
    afoo.funcTwo() // Infinite recursion unless funcTwo is defined on *AFoo
    }

    Not sure why (or even if) it recurses indefinitely, but I can see why
    it doesn't work:

    1. When we call afoo.funcTwo(), there is no explicit method on type
    aFoo, so we look inside the structure. We find a field of type B, an
    interface, with funcTwo defined, so we'll call that value's method.
    aFoo.B is set to aFoo, so...

    2. Goto step 1.

    The line marked OK works because you've explicitly asked for the
    concrete method of type A, not the field within.


    -rob

    --
  • Ludovico Gardenghi at Jan 18, 2013 at 12:07 am

    On Thu, Jan 17, 2013 at 15:42:45 -0800, Rob Pike wrote:

    1. When we call afoo.funcTwo(), there is no explicit method on type
    aFoo, so we look inside the structure. We find a field of type B, an
    interface, with funcTwo defined, so we'll call that value's method.
    aFoo.B is set to aFoo, so...
    I see. Actually Gordon managed to simplify my example even more and now
    the "loop" u.I = u at line 9 together with this explanation of yours makes
    everything much less obscure.

    Thank you both.

    Now I'm wondering what's the best way to do what I want to do. Probably
    I should just add the explicit cast to *A (resp. *State) before calling
    the method. I'd prefer a more robust way though (one which doesn't
    diverge if I forget a cast... :)) -- then maybe the solution is to
    try a different approach altogether.

    Ludovico
    --
    <lu@dovi.co> IRC: garden@freenode
    OpenPGP: 1024D/63D2D5D907F89BB8 Jabber/gtalk: gardengl@gmail.com

    --
  • Rob Pike at Jan 18, 2013 at 12:08 am
    Explain your problem, not your solution.

    -rob

    --
  • Ludovico Gardenghi at Jan 18, 2013 at 12:15 am

    On Thu, Jan 17, 2013 at 16:08:13 -0800, Rob Pike wrote:

    Explain your problem, not your solution.
    I'm building a small state machine for a net/texproto based server. I
    tried the approach used by nsf in his post (see my first one), where the
    only method defined on a state (Test()) has to be defined per-state.

    I'd like to add some generic methods (defined only once, not once per
    state) I can call. E.g. a wrapper for Test() which does some logging
    before calling the actual state handling/transition method, or other
    error reporting/logging/... methods.

    Even better, I'd like to be able to add a generic method that can be
    overridden/specialized if needed for a specific state. This is much less
    important, though.

    Ludovico
    --
    <lu@dovi.co> IRC: garden@freenode
    OpenPGP: 1024D/63D2D5D907F89BB8 Jabber/gtalk: gardengl@gmail.com

    --
  • Andy Balholm at Jan 18, 2013 at 12:32 am

    On Thursday, January 17, 2013 4:14:57 PM UTC-8, garden wrote:

    I'd like to add some generic methods (defined only once, not once per
    state) I can call. E.g. a wrapper for Test() which does some logging
    before calling the actual state handling/transition method, or other
    error reporting/logging/... methods.
    It would probably be better to use functions instead of methods for those,
    taking the state as a parameter.

    --

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedJan 17, '13 at 11:23p
activeJan 19, '13 at 12:57a
posts13
users6
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase