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

Is there a simple way to say: transition from each state for specific event ? #328

Open
lumpidu opened this issue Apr 3, 2020 · 2 comments

Comments

@lumpidu
Copy link

lumpidu commented Apr 3, 2020

How can I use a simple way to say: transition always to a specific state with a specific event, without having to specify this event for each state of the state machine ?

In my example, I am trying to transition to the "aborted"_s state from everywhere, if an event onAbort is sent.

I could rearrange the state machine to be hierarchic, but I want to avoid that.

So I have tried the following:

#include <boost/sml.hpp>
#include <cassert>
#include <iostream>

namespace sml = boost::sml;

namespace {
struct e1 {};
struct e2 {};
struct onAbort {};

struct states {
  auto operator()() const noexcept {
    using namespace sml;
    return make_transition_table(
      state<_> + event<onAbort> = "aborted"_s
      , "aborted"_s + sml::on_entry<_> / [] { std::cout << "aborted on entry" << std::endl; }
      , *"s1"_s + event<e1> = "s2"_s
      , "s1"_s + sml::on_exit<_> / [] { std::cout << "s1 on exit" << std::endl; }
      , "s2"_s + sml::on_entry<_> / [] { std::cout << "s2 on entry" << std::endl; }
      , "s2"_s + sml::on_exit<_> / [] { std::cout << "s2 on exit" << std::endl; }
      , "s2"_s + event<e2> = X
    );
  }
};
}  // namespace

int main() {
  sml::sm<states> sm;
  sm.process_event(e1{});
  sm.process_event(onAbort{});
  sm.process_event(e2{});
}

My expectation:

s1 on exit
s2 on entry
s2 on exit
aborted on entry

But the outcome is:

s1 on exit
s2 on entry
s2 on exit
@Sulter
Copy link

Sulter commented Apr 21, 2020

@lumpidu
I don't think this is a thing in UML, so it's not a thing (and will never be?) in sml.
You probably want to be using composite state:
https://boost-experimental.github.io/sml/examples.html#composite

UML example of leaving any state in "Configuring" on EvConfig by using composite state:

image

@GuiCodron
Copy link
Contributor

GuiCodron commented Jul 29, 2020

Like @lumpidu I think that composite state is the solution to your problem.
In your case, you sm would become:

#include <boost/sml.hpp>
#include <cassert>
#include <iostream>

namespace sml = boost::sml;

namespace {
struct e1 {};
struct e2 {};
struct onAbort {};

struct states {
  auto operator()() const noexcept {
    using namespace sml;
    return make_transition_table(
      *"s1"_s + event<e1> = "s2"_s
      , "s1"_s + sml::on_exit<_> / [] { std::cout << "s1 on exit" << std::endl; }
      , "s2"_s + sml::on_entry<_> / [] { std::cout << "s2 on entry" << std::endl; }
      , "s2"_s + sml::on_exit<_> / [] { std::cout << "s2 on exit" << std::endl; }
      , "s2"_s + event<e2> = X
    );
  }
};
struct error_mgt {

  auto operator()() const noexcept {
    using namespace sml;
    return make_transition_table(
      *state<states> + event<onAbort> = "aborted"_s
      , "aborted"_s + sml::on_entry<_> / [] { std::cout << "aborted on entry" << std::endl; }
    );
  }
};
}  // namespace

int main() {
  sml::sm<error_mgt> sm;
  sm.process_event(e1{});
  sm.process_event(onAbort{});
  sm.process_event(e2{});
}

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

3 participants