CppCon 2018: Kris Jusiak “State Machines Battlefield - Naive vs STL vs Boost”

แชร์
ฝัง
  • เผยแพร่เมื่อ 29 พ.ย. 2024

ความคิดเห็น • 35

  • @TheLavaBlock
    @TheLavaBlock 6 ปีที่แล้ว +6

    Yeah!!! *goto* is back: 27:42
    Thanks for the talk.

  • @trisymphony
    @trisymphony 6 ปีที่แล้ว +18

    So, in summary: The naive implementations are the shortest and easiest to write and understand, produce very few lines of assembly, run the fastest most of the time and work on ancient compilers. It's a tough decision which approach to choose in your next project...

    • @andreaspokorny3089
      @andreaspokorny3089 6 ปีที่แล้ว +3

      If all you do is write three state programs.. that never get extended or maintained.

    • @trisymphony
      @trisymphony 6 ปีที่แล้ว +3

      I work mostly with game code, so performance is the number one concern, followed by cross platform/compiler compatibility. State machines for players, enemies, etc. are the majority of the game logic. In the battle between performance and being safer to work with, performance always wins in games.

    • @andreaspokorny3089
      @andreaspokorny3089 6 ปีที่แล้ว +1

      Take a look at the library examples that contain more states / actions / guards and compound state. You will see that the compiler is capable of seeing through that, and still capable of inlining the transition handling. A three state example is unsuitable to show the pain of growing a switch case/if-else solution.

    • @loomismeister
      @loomismeister 6 ปีที่แล้ว +2

      That's actually pretty subjective, not an inherent truth to game development. For many people, delivering a functional product might be much more important than performance.

    • @Adolf1Extra
      @Adolf1Extra 6 ปีที่แล้ว +2

      Or just throw enough artists at the game to make it look pretty, make it console exclusive and people will label is cinematic experience GOTY contender.

  • @MrAbrazildo
    @MrAbrazildo ปีที่แล้ว

    Nice ideas, but I like and trust the switch/enum approach. I once wrote a PGN (text file, containing several chess games) reader/writer. It worked with states, because almost all characters had different meaning, according to the state/section/stage it was currently reading.
    I kept a switch of the current character, dealing in each case with all states, this time not in a block of ifs nor switch, just a "spaghetti" code actually. Because there were some behaviours that could be reused for different states - _I love compact code, and think it's better to find bugs_ . If I instead had used a switch of states on the 1st place, each case would has a giant switch of characters, which would be awkward.
    For enum, I started with the header and moves. Later, I added things that the user could write by hand, like commentaries and (alternative moving) lines, resulting in new states.
    I used OO, because the user could save the game at any time, so those data from the game should be well hidden and secured.
    Everything worked nicely, like a high level language. Of course I faced many easy-to-find bugs, as in any normal project. But I don't remember ever spending more than 1h catching any of those. Each error was just a matter to look at the output, to know were it read wrongly. If it was a bit harder, I took a pick on the file itself.

  • @Firestar-rm8df
    @Firestar-rm8df ปีที่แล้ว +1

    ....what? Just use a switch function with dispatch to functions that use the enum as a template parameter. Then wrap away the cases with a macro that is configured to be self repeating with substitutions for the specific enum. The compiler will even warn you if you miss one if you omit default, and the switch is skipped at runtime if you've used casting to convert to an out of range enum(which is bad, I'm not saying you should do it, just that this doesn't preclude use of the technique) As a bonus you can define the functions inline and the compiler is allowed to inline away all the overhead of the function calls. Wrap your enum in std::atomic and it's now re-entrant and thread safe(Though, again, please don't do this as every time I've seen it in practice it is much more of an anti pattern. PLEASE just set a flag instead, or a bitmask and read the update from their to handle the state transition). This also makes all your states easily searchable by the enum keys, and you can define the implementation in a separate file. And I'm pretty sure that most of that will work even on older compilers. I know it runs with c++17 support. I think the newest feature you need is function templates though. Also, class enums are a pain if you *want* them to be implicitly convertible in places, so I often use namespace Name{ enum Type{ZERO=0, ONE, TWO}; } but I replace "Name" with the enum name, in this case State. This still provides scoping so you don't clutter the namespace, and you can reference the type with State::Type which I quite like as it's very explicit that it is a type(which I find can sometimes be unclear if a codebase has poor style) If that really bothers you though, you can also leverage a using alias to define the type however you wish(Perhaps StateT(don't use State_t as the _t suffix is actually reserved in various environments and you may accidently generate a collision)

  • @sebastianschweigert7117
    @sebastianschweigert7117 ปีที่แล้ว

    15:38 "need to allocate on the heap" WRONG! Ever heard of a buffer (ie. Placement new). And that's your only criticism that I can see. Yet it's MUCH easier to use and more capable than the boost solution. Therefore, it wins.

  • @LesleyLai
    @LesleyLai 5 ปีที่แล้ว +2

    Use enum for simple case and use his sml library when you need to. Do not use other options he mentioned.

  • @ctrlaltdebug
    @ctrlaltdebug 6 ปีที่แล้ว +2

    What about good old switch + goto coroutines?

  • @rustup5466
    @rustup5466 5 ปีที่แล้ว +1

    State machine and Behavior tree is very good abstraction for working flow. (Make debugging a lot easier.)

  • @xavierthomas1980
    @xavierthomas1980 6 ปีที่แล้ว +1

    The link to the coroutine code sample godbolt.org/Z/SG106R does not work for me.

  • @donaldlace3209
    @donaldlace3209 6 ปีที่แล้ว +6

    Oh dear. you don't use coroutines to implement state machines , coroutines **replace** state machines.

  • @BrutusPalmeira
    @BrutusPalmeira 4 ปีที่แล้ว

    I was gonna go for MSM because of the 'ultra fast' references in the docs but maybe SML will be good enough to get started with... Thanks for the video. I'm sure it was a lot of work to put together all the details.

  • @cicciobombo7496
    @cicciobombo7496 6 ปีที่แล้ว +18

    Take a shot of vodka everytime he says "ya know"

  • @IceBug1337
    @IceBug1337 6 ปีที่แล้ว +1

    The proper way to implement it with a switch is one switch over all states. Call that regularly. If you need to change input for the state machine from other tasks ... let them set an input via setter.
    This way you have all states in one big switch. Add states? Just add a case. Modify a transition? Check out the state from which the transition leaves.
    Say you have state A and state B and Output O and B changes O from 5 to 6. if you transition from A to B the change of the output will occur one cycle later. Say:
    Void Cyclic_Worker()
    {
    Switch(state)
    Case A:
    Output = 5
    if (transition needed)
    State = B
    break
    case B:
    Output = 6
    if (other_transition_needed)
    State = A
    }
    If you need the state change and the output change on the same cycle, do two switches, one for the state change and then for the output
    Of course you can write functions for the cases to make it more readable and manageable once it gets bigger

  • @petermuller9518
    @petermuller9518 6 ปีที่แล้ว

    Great library, have used it myself in a Coupe of projects! Hope it will be included in Boost

  • @bobbymah2682
    @bobbymah2682 6 ปีที่แล้ว

    Great talk, thanks for the library

  • @AK-vx4dy
    @AK-vx4dy 2 ปีที่แล้ว

    Great talk. But... i think you gone wrong with coroutines. co_await, co_return and co_yield are for elide writing state machines by hand and you used them to handmade state machine again... So this "strange" code is a result of this.
    It's diffrent way of thinking but this change of thinkg must be level up at level "do i need manual sate machine?"

  • @bit2shift
    @bit2shift 6 ปีที่แล้ว +6

    Putting _const_ after the type is an awful eyesore.

    • @bitbangs
      @bitbangs 6 ปีที่แล้ว +2

      consistent const. i find it easier to read but difficult to get people on board :)

    • @bit2shift
      @bit2shift 6 ปีที่แล้ว

      @@bitbangs consistent is saying that *_const_*_ T& t_ is a reference to a _T_ constant, while _T& t_ is a reference to a _T_ variable.

    • @bitbangs
      @bitbangs 6 ปีที่แล้ว

      i got my "consistent const" lingo from here:
      isocpp.org/wiki/faq/const-correctness#const-ref-alt

    • @bit2shift
      @bit2shift 6 ปีที่แล้ว +1

      ​@@bitbangs "whereas the other style _sometimes_ puts the const on the left and _sometimes_ on the right."
      If that *"(...) **_sometimes_** on the right."* refers to constant pointers (char* const p), I have pratically no use for them.

    • @xavierthomas1980
      @xavierthomas1980 6 ปีที่แล้ว +4

      "east const" vs "const west" was the bikeshed topic of last year's conference

  • @movax20h
    @movax20h 4 ปีที่แล้ว +1

    The examples show are very contrived and simplistic. They don't tell real story in real code. Equating assembler code length to performance is totally silly. There is so many other things that are important. There shouldn't be any difference between switch, if and fold
    expressions. They are all just conditions to the compiler. However, the
    problem is you are comparing constant propagation and folding by the
    compiler, not actual generated code where there events are dynamically
    coming from somewhere else (file, network, other subsystem). There are
    no benchmarks at all in the presentation. Just glancing at irrelevant
    assembly code.

  • @schleppel12
    @schleppel12 6 ปีที่แล้ว +7

    Interesting topic, but the presentation wasn't that enjoyable. Lots of too long awkward pauses(and then just saying "This is bad!" or "This is good!") and "um" "ya know" and other fillers.

  • @bernadettetreual
    @bernadettetreual 6 ปีที่แล้ว +1

    "The STL is one of the best libraries available" 😂 Nice joke. It's only a specification and varies significantly in quality.

  • @leopardenforelle
    @leopardenforelle 6 ปีที่แล้ว

    I like you. But probably not your best presentation...