You describe the events, transitions and even interrupts and this compiles to optimized goto statements with no allocation, no indirect function calls, no switch statement.
There are compile-time checks to make sure you don't have state with no transition from and it also produce a visual graph of your state and transitions.
It's been tuned to be used as the core of my high performance multithreading runtime so zero overhead compared to handwritten.
It is suitable for any state machine with zero alloc constraint and state machines can be composed (they are just a function).
I hope in the future to be able to add model checking using Nim Z3 integration so that we can reach Ada/Sparks formal verification prowess: https://github.com/nim-lang/RFCs/issues/222
wrt to the SMT integration, it's something that I would very much like to try in D, but it's quite difficult to work out exactly where to start (and means bolting a fairly big dependency on the compiler). There also seems to be a big gap in the literature between "practical" verification done "in" the widget being verified (e.g. SystemVerilog code) and more academic work where, effectively, a parallel structure is built which represents the semantics of the widget.
It's an interesting pattern to test language designs with. On the one hand expressive macros can be disastrous in big codebases, on the other hand a more "monadic" (implemented via passing some kind of object through a chain rather than algebraically) way is very template-intensive.
[1] https://github.com/c-blake/cligen/blob/master/cligen/macUt.n...
For this same reason I really dislike that in C++ you can just implicitly drop the "this->" to target class members. You can never tell at a glance what "foo = blah" does if you don't know whether "foo" is a member of "this" or not.
I think your page demonstrates what I mean in the "nested WithStatement" example:
Foo foo;
Bar bar;
Baz baz;
f(); // prints "f"
with(foo)
{
f(); // prints "Foo.f"
with(bar)
{
f(); // prints "Bar.f"
with(baz)
{
f(); // prints "Bar.f". `Baz` does not implement `f()` so
// resolution is forwarded to `with(bar)`'s scope
}
}
with(baz)
{
f(); // prints "Foo.f". `Baz` does not implement `f()` so
// resolution is forwarded to `with(foo)`'s scope
}
}
with(baz)
{
f(); // prints "f". `Baz` does not implement `f()` so
// resolution is forwarded to `main`'s scope. `f()` is
// not implemented in `main`'s scope, so resolution is
// subsequently forward to module scope.
}
WiI get that sometimes it can cut on a lot of repetition, but I think I would be fine if the syntax was more explicit while still avoiding repetition, for instance:
with (some_object) {
.some_member = 1;
.some_other = 4;
not_a_member = .some_method();
}
And beyond that make it non nestable (i.e. only the first level of "with" is taken into account) to avoid the situation above with complicated overloading.In my experience that would account for 99% of uses of `with` while making the code a lot more readable without requiring a lot of context to make sense of it.
Although frankly even that might arguably overkill, for dynamic languages or ones with type inference you might as well just do something like:
{
let v = &mut some_annoyingly.long.thing();
v.foo = bar;
v.baz();
}
It's almost the same amount of typing and you don't need any magic.My preference is Nim over D primarily since Nim compiles to C, but also overall the community appreciates syntax sugar but also has a decent sense as to when and how to use it. Most "sugar" in Nim needs to be explicitly imported. Literally `import sugar` is one of my first lines in many files.
let v = &mut some_annoyingly.long.thing();
v.foo = bar;
v.baz();
In the example you list (is that Rust, or D?), if it was in C or Nim and those were structs-within-structs and not pointers/refs then `.thing` would be copied to a new `v` (if I recall the semantics correctly). So you'd end up with a weird "logic" bug where updates would disappear. The Nim `with` macro solves that by modifying the generated code,
D also has withs. Definitely in the "not necessary but nice to have" category of features, particularly when implementing state machines (i.e. statment soup)