LINUX.ORG.RU

История изменений

Исправление zurg, (текущая версия) :

возьмём один из базовейших сценариев - конечные автоматы, нужны на всех уровнях айтишечки, желательно типобезопасные особенно для системщины, на плюсах находится что-нибудь такое(https://github.com/qlibs/sml):

// events
struct connect {};
struct established {};
struct ping { bool valid{}; };
struct disconnect {};
struct timeout {};

int main() {
  // guards/actions
  auto establish = [] { std::puts("establish"); };
  auto close     = [] { std::puts("close"); };
  auto reset     = [] { std::puts("reset"); };

  // states
  struct Disconnected {};
  struct Connecting {};
  struct Connected {};

  // transitions
  sml::sm connection = sml::overload{
    [](Disconnected, connect)      -> Connecting   { establish(); },
    [](Connecting,   established)  -> Connected    { },
    [](Connected,    ping event)                   { if (event.valid) { reset(); } },
    [](Connected,    timeout)      -> Connecting   { establish(); },
    [](Connected,    disconnect)   -> Disconnected { close(); },
  };

  static_assert(sizeof(connection) == 1u);
  assert(connection.visit(is<Disconnected>));
  assert(connection.process_event(connect{}));
  assert(connection.visit(is<Connecting>));
  assert(connection.process_event(established{}));
  assert(connection.visit(is<Connected>));
  assert(connection.process_event(ping{.valid = true}));
  assert(connection.visit(is<Connected>));
  assert(connection.process_event(disconnect{}));
  assert(connection.visit(is<Disconnected>));
}

корявенько и мутно со всеми этими visit, overload и лямбдами, и это ещё современные плюсы и это для них максимум выразительности . Более менее прямой аналог на расте:

enum Event {
    Connect,
    Establ,
    Ping(bool),
    Disconnect,
    Timeout,
}
#[derive(Debug, PartialEq)]
enum State {
    Disconnected,
    Connecting,
    Connected,
}
impl State {
    fn process_event(&mut self, ev: Event) -> &Self {
        use Event::*;   use State::*;
        *self = match ev {
            Connect => {
                est();
                Connecting
            }
            Establ => Connected,
            Ping(valid) => {
                if valid { reset(); };
                Connected
            }
            Timeout => {
                est();
                Connecting
            }
            Disconnect => {
                close();
                Disconnected
            }
        };
        self
    }
}
pub fn main() { 
    let mut conn = State::Disconnected;
    assert!(conn == State::Disconnected);
    assert!(conn.process_event(Event::Connect) == &State::Connecting);
    assert!(conn.process_event(Event::Establ) == &State::Connected);
    assert!(conn.process_event(Event::Ping(true)) == &State::Connected);
    assert!(conn.process_event(Event::Disconnect) == &State::Disconnected);
    println!("sizeof = {}", size_of::<State>());
}

компилится https://godbolt.org/z/EK5eKGcso примерно в тоже самое (смотреть main() ) , и это без доп. библиотек из коробки, по ясности- красивости даже в питоне лучше не получиться, если только в хачкеле каком-нибудь. И это ещё самое простое для рачта, если по полной расчехлить растовый тайпстейт вменяемый аналог на плюсах вообще не получится написать

Исходная версия zurg, :

возьмём один из базовейших сценариев - конечные автоматы, нужны на всех уровнях айтишечки, желательно типобезопасные особенно для системщины, на плюсах находится что-нибудь такое(https://github.com/qlibs/sml):

// events
struct connect {};
struct established {};
struct ping { bool valid{}; };
struct disconnect {};
struct timeout {};

int main() {
  // guards/actions
  auto establish = [] { std::puts("establish"); };
  auto close     = [] { std::puts("close"); };
  auto reset     = [] { std::puts("reset"); };

  // states
  struct Disconnected {};
  struct Connecting {};
  struct Connected {};

  // transitions
  sml::sm connection = sml::overload{
    [](Disconnected, connect)      -> Connecting   { establish(); },
    [](Connecting,   established)  -> Connected    { },
    [](Connected,    ping event)                   { if (event.valid) { reset(); } },
    [](Connected,    timeout)      -> Connecting   { establish(); },
    [](Connected,    disconnect)   -> Disconnected { close(); },
  };

  static_assert(sizeof(connection) == 1u);
  assert(connection.visit(is<Disconnected>));
  assert(connection.process_event(connect{}));
  assert(connection.visit(is<Connecting>));
  assert(connection.process_event(established{}));
  assert(connection.visit(is<Connected>));
  assert(connection.process_event(ping{.valid = true}));
  assert(connection.visit(is<Connected>));
  assert(connection.process_event(disconnect{}));
  assert(connection.visit(is<Disconnected>));
}

корявенько и мутно со всеми этими visit, overload и лямбдами, и это ещё современные плюсы и это для них максимум выразительности . Более менее прямой аналог на расте:

enum Event {
    Connect,
    Establ,
    Ping(bool),
    Disconnect,
    Timeout,
}
#[derive(Debug, PartialEq)]
enum State {
    Disconnected,
    Connecting,
    Connected,
}
impl State {
    fn process_event(&mut self, ev: Event) -> &Self {
        use Event::*;   use State::*;
        *self = match ev {
            Connect => {
                est();
                Connecting
            }
            Establ => Connected,
            Ping(valid) => {
                if valid { reset(); };
                Connected
            }
            Timeout => {
                est();
                Connecting
            }
            Disconnect => {
                close();
                Disconnected
            }
        };
        self
    }
}
pub fn main() { 
    let mut conn = State::Disconnected;
    assert!(conn == State::Disconnected);
    assert!(conn.process_event(Event::Connect) == &State::Connecting);
    assert!(conn.process_event(Event::Establ) == &State::Connected);
    assert!(conn.process_event(Event::Ping(true)) == &State::Connected);
    assert!(conn.process_event(Event::Disconnect) == &State::Disconnected);
    println!("sizeof = {}", size_of::<State>());
}

компилится https://godbolt.org/z/EK5eKGcso примерно в тоже самое (смотреть main() ) , только без лишних библиотек, по ясности- красивости даже в питоне лучше не получиться, если только в хачкеле каком-нибудь. И это ещё самое простое для рачта, если по полной расчехлить растовый тайпстейт вменяемый аналог на плюсах вообще не получится написать