Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Mark Truluck
    @frame-lang
    So far the Frame community is very northwest centric. I have wonder if Reddit is overweighted that way...
    Well welcome John. What languages do you typically use? Rust has been the focus as of late.
    john-j-mclaughlin
    @john-j-mclaughlin
    Well, I was a C/C++ guy for decades. But, as of late, I am using Go for the production code and Python in development support roles. Been planning to give Rust a tryout, but time has not allowed for that, yet.
    Mark Truluck
    @frame-lang
    Cool! Generating Go is on the shortish term list of things to do as it would be good for me to know. It would be great to have an expert trying to make use of it (and any of the other languages for that matter). LMK if you are interested in giving it a try - I am eager to have people putting it to use. If you would like more info about Frame first I'll be hosting another intro session in a couple of weeks.
    Also would be very interested in any patterns you like for implemeting statecharts in C. That is another target language I want to tackle soonish
    john-j-mclaughlin
    @john-j-mclaughlin
    Mark, it seems we are on the same path with regard to HFSM-based software development. We built a DSL with a concise and intuitive grammar and full Harel/UML support back in the 90's which generated production quality ANSI C code. More recently, I have redesigned and reimplemented the same capabilities with Go as the target (however, the new version can really target practically any language). It also has a very rich set of event publishing and handling capabilities. Let me know if you want to see some sample code.
    It's fairly performant already without any code optimization, handling about 1M events and state transitions per second on my couple year old laptop.
    Mark Truluck
    @frame-lang
    I would love to see any examples of your technology - it sounds impressive. Who is involved with the project and is a company backing it? Have you open sourced it?
    john-j-mclaughlin
    @john-j-mclaughlin

    In the 90's I had a small consulting company specialized in factory automation. The FSM (and other) technology was done by me and my team and was funded by a $750K project we had won. It was later used in many other automation contracts, and in fact is still running some fabs 24x7 yet today.

    The rewrite I have done myself, taking all the concepts and lessons learned and using more modern tools, such as a modern Parser Generator. The original was done with Yacc/Lex.

    Re: Open Sourcing it... I have never really understood the benefit to giving away software, unless it's something that warrants a group effort in development. And for those, my experience so far has been if it's needed, someone will usually fund the development. But, I am still open to the idea of open sourcing it.

    john-j-mclaughlin
    @john-j-mclaughlin

    Here's a trivial example of the new version. It shows only a few of the features but gives a decent introduction. Since I did not want to repeat the previous approach (full ANSI C parsing, or in this case Go) I enclose the desired "target language" fragments in ${ ... $} blocks. Handler code can (but is not required to) be added to any event or timer handler, as well as to state entry and/or exit blocks. As I mentioned, there's a lot more possible with events (matching and delivery options), and more state constructs, as well.

    https://gist.github.com/john-j-mclaughlin/6c1b3912b40ca78fdab3c2bef0e24e4b

    Let me know if you have questions.

    Mark Truluck
    @frame-lang
    Cool! Looks like an elegant syntax. I would like to know a lot more. What is the language called? Do you have any documentation?
    Mark Truluck
    @frame-lang
    I've started a wiki to track release goals and work here: https://github.com/frame-lang/frame_transpiler/wiki/Framepiler-v0.6
    john-j-mclaughlin
    @john-j-mclaughlin
    No documentation, yet. But, my feeling is that the language is intuitive enough it won't need much. Some basic explanations, syntax rules and some working samples should be plenty.
    Mark Truluck
    @frame-lang
    Well happy to help promote it on r/state machines if that is useful. I’m interested in what kind of built in timers and other event mechanisms you’ve come up with.
    john-j-mclaughlin
    @john-j-mclaughlin
    Here's another contrived example FSM modelling a 2-switch light fixture. When both switches are up, or both are down, then the light is on. Else, it's off.
    Mark Truluck
    @frame-lang
    Cool and thanks for sharing. There may be some great ideas in there for frame.
    Mark Truluck
    @frame-lang
    Bringing this conversation over from the Rust discussion. I am curious about people's thoughts on the implications of an event handler being able to execute additional statements after a transition. I see pros and cons and do believe the more intuitive design decision would be not to permit it. However in the past I played with some scenarios where the event handler acted sort of like a client for the state machine and drove the machine's activity just like an external client would.
    $S1
       |e1|
           -> $S2
           e1() ^
    So in this case the $S1:|e1| handler could capture an event, transition to a better state to handle it in and then recall the interface directly to handle it in $S2. If it was parameterized it could be even more useful so as to modify the event for some reason (perhaps to indicate the event happened in an unexpected/incorrect state initially)
    john-j-mclaughlin
    @john-j-mclaughlin
    What's the difference between
    1. executing some code associated with the event (assuming the FSM is in a valid state to process that event) and transitioning to a new state
      and
    2. transitioning to a new state and executing some code associated with the event?
      I see no distinction.
    john-j-mclaughlin
    @john-j-mclaughlin
    Unless you're assuming the event code is dependent upon the new state's "on entry" code having already run. In which case this sounds like a brittle approach.
    Eric Walkingshaw
    @walkie

    Some differences between executing code after a transition vs. the enter handler for the new state:

    1. There may be several different ways to transition into the new state and we don't want to execute the code for all of them. This could be worked around by passing a flag as a transition argument, but this complicates the code in other ways since now that argument must be passed whenever we transition to that state.

    2. Code executed after the transition can use variables in scope in the current handler. This can also be worked around by passing transition arguments, but now things get really messy if we have multiple ways to enter the new state.

    I'm not sure how important either of these scenarios are in real systems, and I like the appeal of the simpler model. However, I also think there's an argument for supporting mid-handler transitions for expressiveness reasons, even if we don't have concrete applications in mind.

    My general philosophy in language design is to err on the side of expressiveness unless there are specific correctness/safety criteria we have in mind that would be violated. In this case, the criterion could be "the last code associated with a state that is executed is the exit handler". If that is a criterion we want, then we should disallow mid-handler transitions. If that is not a criterion that we care about (and there isn't some other one that would be violated), then we should allow it by default.

    Eric Walkingshaw
    @walkie
    Always helpful to write down these kinds of criteria as we discover them too since it helps to make more consistent/informed design decisions in the future.
    Mark Truluck
    @frame-lang
    Great discussion and I gotta say I'm really excited to start to get into this level of thinking about how to state machine systems ought to be designed and used . One of the goals I had in creating Frame was to make these kinds of questions easier to see and discuss and not be buried in the details of the target languages.
    I'll add some more thoughts later
    john-j-mclaughlin
    @john-j-mclaughlin

    To address the type of behavior you describe, I have used 1 of 2 approaches in the past. The first is with substates of the target state, where the substate reflects how it got there. The substate can have "how" related code to execute, and the common parent would have the general state code.

    The second approach is supported in my implementation... All handler code (state_entry, state_exit, on_event, on_timer, etc.) has access to the triggering event so this code can have conditional logic based on the event.

    I generally find the first approach preferable since it's exposed in the FSM structure and is therefore documented.

    Eric Walkingshaw
    @walkie
    Thanks, John. I'm a lot less familiar with using state machines in practice, so good to know there are patterns for recovering this behavior in a sane way if mid-handler transitions are removed.
    john-j-mclaughlin
    @john-j-mclaughlin
    Eric, I re-read what you were asking about and I may have read more complexity into the question that was actually present. If you were asking how to get code associated with the event, and not with the target state, it's even more simple. In my grammar it would be expressed something like this:
    state_machine(fsm) {
    
        state(A) {
            on_event("Event_1", ../B) ${
                // code to execute when Event_1 occurs in state A
                // followed by transition to state B
            $}
            on_event("Event_2", ../B) ${
                // code to execute when Event_2 occurs in state A
                // followed by transition to state B
            $}
            on_entry ${
                // code to execute when entering state A
            $}
        }
    
        state(B) {
            on_entry ${
                // code to execute when entering state B
            $}
        }
    }
    Eric Walkingshaw
    @walkie

    I think you read the proper amount of complexity the first time! :-)

    The problem is if you have code you want to execute on Event_1 (and not on Event_2) after the transition to state B. Currently, Frame allows you to specify a transition in the middle of an event handler, so you can (1) do some stuff, (2) transition to B, (3) do some more stuff in the same context that you did (1). You can't put the stuff from (3) in the on_entry handler for B because it shouldn't be executed if we reach B via Event_2.

    Your solution with sub-states solves this, I think, because then you can put the stuff from (3) in the on_entry handler for the corresponding sub-state. However, there is still the problem of what if the stuff from (3) depends on variables in scope in the A.Event_1 handler? You can pass all this information along, but now things are getting more complicated.

    I don't have a concrete use case for this in mind and I'm not opposed to deciding for other reasons that they should be disallowed. Just trying to highlight that mid-handler transitions do provide some expressiveness that is lost by forbidding them. Note here that I don't mean "expressiveness" in the absolute sense (I'm sure both approaches can ultimately do the same thing) but rather in the practical sense (you have to jump through more hoops to do it without this feature, e.g. use sub-states and propagate the needed variables along via arguments).

    john-j-mclaughlin
    @john-j-mclaughlin
    Well, I guess the 2nd approach would look like this:
    state_machine(fsm) {
    
        state(A) {
            on_event("Event_1", ../B);
            on_event("Event_2", ../B);
            on_entry ${
                // code to execute when entering state A
            $}
        }
    
        state(B) {
            on_entry ${
                // code to execute when entering state B
                switch sourceEvent.id {
                case "Event_1":
                    // code to execute when entering state B from Event_1
                case "Event_2":
                    // code to execute when entering state B from Event_2
                }
                // code to execute when entering state B
            $}
        }
    }
    Eric Walkingshaw
    @walkie
    Yeah, that looks nice (although the scope is still different!) but Frame doesn't have a way to access the source event, as far as I know, so you'd have to pass in a parameter to match on.
    john-j-mclaughlin
    @john-j-mclaughlin
    Not sure what "scope" you refer to. This is not like a call stack frame. The "variables" which need to be persisted for later access are just member attributes of the state machine root object, or of one of the substate objects.
    The data for an event (if any is required) are just properties of the event object and are accessible by any handers invoked by the event.
    Eric Walkingshaw
    @walkie
    That's not the way frame works though, which is the language we're making this decision about. :-) In Frame, there are potentially state variables, state parameters, and event parameters, which would all be in scope in a handler in state A, and would not be in scope in the on_entry handler in state B, and there would be no way to access them any more from the handler in state B.
    john-j-mclaughlin
    @john-j-mclaughlin
    Ah... OK... I cannot speak specifically to Frame :)
    Mark Truluck
    @frame-lang
    Just wrapped up the day and finally have a moment to comment but looks like a great discussion. I can argue it either way theoretically but there may be a forcing function that dictates a particular decision. In v6.0 I want to make the transition type to be configurable. Currently all transitions are what I'm thinking to call "immediate". As we have been discussing, I would like to get "deferred" transitions in next. If it was confusing to have actions happen after an immediate transition, it would be nonsensical to have them after a deferred transition. In effect, for deferred, one would always execute all actions prior to the transition regardless of if you specified them before or after the transition because, well, the the transitions were deferred :).
    So as to not have completely different behavior between the two architectures, I am leaning towards having the grammar enforce a return immediately after a transition. What do ya'll think?
    The deferred architecture example: https://dotnetfiddle.net/rQaB9R
    Mark Truluck
    @frame-lang
    On a different point that was raised - the frame event is referenceable using the @ token. Search for Frame Event here: https://frame-lang.org/notation/
    You can also reference it's component parts as well and pass the event as well as its parts to actions
    action1(@ @|| @["p1"] @^) // etc
    So I believe you can pass the "source event" to an interface call like this (but haven't tried it yet :) )
    iface1(@)
    Mark Truluck
    @frame-lang
    I'll give it a try later.
    Eric Walkingshaw
    @walkie
    Hi Mark, that makes sense to me. I'll adjust my (still in progress...) refactor of the Rust backend to only support transitions at the end of the handler. Currently, since the frontend doesn't rule these programs out, the backend will just generate code that doesn't compile (due to an ownership issue). But once the frontend is modified to enforce returns after transitions, hopefully the errors will be a bit more comprehensible.
    Mark Truluck
    @frame-lang
    Considering the use of https://readthedocs.org/ for documentation. I agree getting the grammar documented is a top priority. Any other ideas for the documentation?
    I found that resource when learning Godot: https://docs.godotengine.org/en/stable/index.html
    Eric Walkingshaw
    @walkie

    Using readthedocs.org seems like a solid choice to me.

    The documentation that you have already on frame-lang.org is a great start I think. Just needs to be expanded a bit and a way to make it easier to navigate. Using readthedocs.org should be good for that because you'll get section header links in the menu and so on, which will help a lot.

    The demos you have linked at the bottom of this page were also very helpful to us getting started. Might be worthwhile to have one medium complexity example like this that is explained piece-by-piece in the documentation, as a sort of tutorial. Then you can just include links to other examples like you have already.

    Bradley Nelson
    @bradnelson
    I've liked readthedocs as well :thumbsup: (Also came across it when learning Godot!)