Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I would not really call that a state machine. (Or a parser.) Which were the topic at hand. All of my state machine have been for embedded targets and generally look like

    rules(struct stateful state) {
        switch (state->foo) {
        case ....
        }
    }

    sensors(struct stateful state) {
        state->button1 = ....
    }

    motors(struct stateful state) {
        switch(state->foo) {
            case ....
            portBar = ....
        }
    }

    main() {
        for(;;){
            sensors(state)
            rules(state)
            motors(state)
        }
     }
Simple state machine, no gotos are needed. Works fine for non-simple ones too. And the first rule of fault tolerant code (particularly for embedded) is never use malloc.

I agree that goto is useful for error handling, but not parsers or state machines. Anyway, I'll play your bait-and-switch. Here is error handling without goto.

    typedef struct thing {
        int id;         /* object ID */
        int buf_sz;     /* current size of the buffer */
        char *buf;      /* internal buffer */
        foo *f;         /* some other thing that needs alloc / init */
    } thing;
    
    thing *thing_new(int id, int buffer_size) {
        do {
            thing *t = malloc(sizeof(*t));
            foo *f = NULL;
            char *buf = NULL;
            if (t == NULL) {break;}
            buf = malloc(buffer_size);
            if (buf == NULL) {break;}
            t->buf = buf;
            f = foo_new();
            if (f == NULL) {break;}
            t->f = f;
            return t;
        } while (0)
        // clean up
        if (f) {foo_free(f);}
        if (buf) {free(buf);}
        if (t) {free(t);}
        return NULL;
    }
Now normally I would never do that. More typically I would actually use the loop. Because I would not be malloc-ing, I would be trying to initialize a piece of hardware over SPI or i2c. The do...while would be replaced with a for(i=maxtries; i; i--) loop. After maxtries, the loop terminates and the peripheral is shut down.


And now, how do you break from within the 2nd and 3rd level of nesting? break can only break one of them. If only "break" had a label, so you could say "break toplevel;" instead of just "break;" (and name the relevant scope "toplevel", of course).

Turns out, you actually can! instead of "break toplevel;", you just write "goto toplevel;". There's another minor change, in that you have to put the name at the end of the scope, rather than the beginning of the scope, which is why people tend to name it after the next block (e.g. "goto cleanup;" in this case).


I do not believe you have actually read any of the conversation.

Still waiting for someone to show me a state machine that absolutely needs goto.


I was only replying to your "here's error handling without goto". And I'm not implying that it is impossible - just that your solution does not scale as is to more than one level of scoping.

There is nothing that absolutely needs goto (including error handling), because Turing completeness does not require goto. so you might wait forever; I'm not sure what it is that you guys are arguing about with respect to state machines.

(of note, I keep waiting for TCO proponents to show me an example in which the guarantee of TCO in scheme makes the world so-much-better. The claim always comes up, and every example I've seen so far requires at most adding two more lines in Python, and no adding of TCO)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: