Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entry actions are not called during state machine initialization #50

Closed
Ulenspiegel opened this issue Jun 30, 2016 · 1 comment
Closed

Comments

@Ulenspiegel
Copy link

I've mentioned it in another issue, but only now tested it separately and making an issue of its own. When state machine is created and its initial state configuration is entered, no entry actions are called. Example:

#include <cstdio>
#include <cassert>
#include <boost/msm-lite.hpp>

namespace msm = boost::msm::lite;

using msm::state;
using msm::event;
using msm::sm;
using msm::make_transition_table;

struct e1 {};
struct e2 {};

state<class SubSubState1_1> ss1_1;
state<class SubSubState1_2> ss1_2;

struct SubState1 {
  SubState1() {}
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        *ss1_1 + event<e1> = ss1_2,
        ss1_1 + msm::on_entry / [] { printf("Entering SS1_1.\n"); },
        ss1_2 + msm::on_entry / [] { printf("Entering SS1_2.\n"); },
        ss1_1 + msm::on_exit / [] { printf("Leaving SS1_1.\n"); },
        ss1_2 + msm::on_exit / [] { printf("Leaving SS1_2.\n"); }
    );
  }
};

state<class SubSubState2_1> ss2_1;
state<class SubSubState2_2> ss2_2;

struct SubState2 {
  SubState2() {}
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        *ss2_1 + event<e1> = ss2_1,
        ss2_1 + msm::on_entry / [] { printf("Entering SS2_1.\n"); },
        ss2_2 + msm::on_entry / [] { printf("Entering SS2_2.\n"); },
        ss2_1 + msm::on_exit / [] { printf("Leaving SS2_1.\n"); },
        ss2_2 + msm::on_exit / [] { printf("Leaving SS2_2.\n"); }
    );
  }
};

state<sm<SubState1>> ss1;
state<sm<SubState2>> ss2;

struct TopState {
  TopState() {}
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        *ss1 + event<e2> = ss2,
        ss1 + msm::on_entry / [] { printf("Entering SS1.\n"); },
        ss2 + msm::on_entry / [] { printf("Entering SS2.\n"); },
        ss1 + msm::on_exit / [] { printf("Leaving SS1.\n"); },
        ss2 + msm::on_exit / [] { printf("Leaving SS2.\n"); }
    );
  }
};

int main(int argc, char** argv) {
  SubState1 ss1_;
  sm<SubState1> ssm1_(ss1_);
  SubState2 ss2_;
  sm<SubState2> ssm2_(ss2_);
  TopState s_;
  sm<TopState> m(s_, ssm1_, ssm2_);
  assert(m.is(ss1));
  assert(ssm1_.is(ss1_1));
  return 0;
}

When ran, program shows nothing - asserts confirm that state machine entered desired configuration (ss1(ss1_1)), but entry actions were not called. Since entry actions set identity for states, machine will have not been initialized properly.

Introducing a dummy initial state and anonymous transition helps:

struct TopState {
  TopState() {}
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        *"init"_s = ss1,
        ss1 + event<e2> = ss2,
        ss1 + msm::on_entry / [] { printf("Entering SS1.\n"); },
        ss2 + msm::on_entry / [] { printf("Entering SS2.\n"); },
        ss1 + msm::on_exit / [] { printf("Leaving SS1.\n"); },
        ss2 + msm::on_exit / [] { printf("Leaving SS2.\n"); }
    );
  }
};

Output:

Entering SS1_1.
Entering SS1.

I think action order is still incorrect (see #43), but states are initialized at least. It's not intuitive and error prone though, takes running into the bug to resort to the dummy state.

@kris-jusiak
Copy link
Collaborator

Fixed in 3a962b8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants