Skip to content

Idea: Enums as State Machines #1906

Closed
Closed
@mark-i-m

Description

@mark-i-m

The problem of encoding some sort of state machine is common for many programs, such as building parsers, schedulers, protocols, or coroutines. This proposal extends enums to allow them to express state machines.

Enums would be extended with extra syntax as follows. The design is intended not to break any existing code. Enums would retain all of the features they currently have, but they would also have extra abilities. For example

pub enum MyStates {
    // The `=> State2` denotes that an enum with value `State1` can only
    // have its value changed to `State2`.
    State1(u32) => State2,              

    // A variant can have multiple successor states
    State2 => {State3, State4},
    State3(IpAddr) => {State4, Error},

    // A variant can decide to transition to itself, which means that once
    // the state machine gets into state `Error`, it is stuck there.
    Error => Error,

    // A variant without explicit next states implicitly can transition to any
    // other variant/state. This makes sure that current code does not break.
    State4,
}

I think it should be relatively easy to enforce these constraints in safe code statically with little or no non-local reasoning. (Not 100% sure about this, though... Can someone find a counterexample?). For example,

pub fn advance_fsm(fsm: &mut MyState) {
    match fsm {
        &mut MyState::State1(i) => {
            send_msg(i);
            
            // This assignment can ONLY be to `State2`
            *fsm = MyState::State2;           
        }
        &mut MyState::State2 => {
            // COMPILE ERROR: Illegal state transition: State2 -> State1
            *fsm =  MyState::State1;      
        }
        &mut MyState::State3(ip) => if connect(ip) {
            *fsm = MyState::State4;
        } else {
            *fsm = MyState::Error;
        },
        &mut MyState::State4 => *fsm = MyState::State1,
        &mut MyState::Error => {}
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-langRelevant to the language team, which will review and decide on the RFC.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions