История изменений
Исправление 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() ) , только без лишних библиотек, по ясности- красивости даже в питоне лучше не получиться, если только в хачкеле каком-нибудь. И это ещё самое простое для рачта, если по полной расчехлить растовый тайпстейт вменяемый аналог на плюсах вообще не получится написать