One of my professors had an idea about distributed synchronous programming, but nothing ever came of it.
I have had personal experience delivering the technology in the fields. We implemented the entire safety logic of a driverless train control system using SCADE (hence esterel). Airbus uses it for their onboard computers. So as you can see, this has had massive application around the world.
We worked on a hackathon together where we built a physical chessboard interface (https://github.com/chesseye/chesseye). He built the controller, which handles among other things the output from the video recognizer and messages the chess engine, in ReactiveML. I didn't know much about the language beyond first principles then, but was impressed by how easy it made it to compose parallel processes.
We tried to convey some of those conclusions in a later presentation, even though looking at it 2 years later I realize it's probably hard to get the insights without the verbal delivery: https://github.com/chesseye/chesseye/blob/master/presentatio...
(I understand there was a ReactiveML tutorial at ICFP last Saturday: https://icfp18.sigplan.org/program/program-icfp-2018, not sure if this post is related.)
It shouldn't be too difficult to distribute synchronous languages, and it is a quite natural idea. Most have a semantics based on Kahn networks [1], which is already a distributed model of computation :).
I don't think this is correct. Kahn networks are asynchronous (and therefore well-suited for distributed systems), but synchronous languages are – well, synchronous.
For every pair of nodes that exchange information, there has to be a rendezvous between them after every non-instantaneous step [1], which is terrible for performance in a distributed system (but virtually free in typical single-clocked, synchronous digital circuits).
[1] You can devise heuristics which reduce the frequency of those rendezvous in some cases, but conceptually, they're still there.
#include "arduino/arduino.ceu"
input int PIN_02; // button input
output int PWM_05; // LED outputs, remember that pins 5 and 6
output int PWM_06; // have a higher PWM frequency on the UNO
// a code block that concurrently fades an LED in and out
// `pin` the output pin of the LED
// `min` min value of the fade
// `max` max value of the fade
// `delay` ms to wait between `analogWrite` updates
code/await Fade_forever(var u8 pin, var u8 min,
var u8 max, var uint delay) -> void do
loop do
var int i;
loop i in [min->max[ do // fade in loop
if pin == 5 then
emit PWM_05(i);
else/if pin == 6 then
emit PWM_06(i);
end
await delay ms;
end
loop i in [min<-max[ do // fade out loop
if pin == 5 then
emit PWM_05(i);
else/if pin == 6 then
emit PWM_06(i);
end
await delay ms;
end
end
end
loop do //endless loop
// if *any* of these three code blocks (trails) end,
// all of the remaining trails in a `par/or` are
// aborted and code resumes (in this case, the outer
// loop restarts). By comparison, a `par/and`
// would require *all* of the trails to terminate.
par/or do
// if a button is pressed, reset the loop
await PIN_02;
with
// fade the LED at pin 5 quickly between 64 and 192
await Fade_forever(5, 64, 192, 5)
with
// fade the LED at pin 6 slowly between 0 and 256
await Fade_forever(5, 0, 256, 20)
end
Pretty simple and readable code, don't you think? (Note the use of Bourbaki interval notation for [min -> max[ - how often have you seen that in programming languages?) Now imagine what the plain C version of this would look like.What I also find fascinating about it is that it has almost no memory overhead per trail - a handful of bytes IIRC. Compare that to the kilobytes required for green thread solutions elsewhere. OTOH, computationally the concurrency doesn't really scale with large numbers of trails - I think you could compare it to insertion sort: unbeatable for small arrays due to low overhead, but then that O(n^2) takes over.
One might envision having many small Céu programs with only a handful of trails each, asynchronously running in their own threads and interacting with each other. From what I gather, programming in this model is called using the GALS principle: Globally Asynchronous, Locally Synchronous. For the intended environment for Céu (embedded programming), you kind of "naturally" get this: asynchronicity just kind of "happens" due to separate pieces of hardware interacting.
Anyway, it kind of feels like the "missing element" in reactive and concurrent programming paradigms to me. I hope more languages will start picking it up eventually.
[1] https://www.reddit.com/r/arduino/comments/5qzv12/c%C3%A9uard...
Disclaimer: looks easy, but if you take a few non trivial examples with concurrent state machines and contemplate the resulting C code, you will quickly understand why having a dedicated language is a good idea as opposed to trying to do it by hand.
The paradigm is also adapted to graphical programming (using boxes and wires) which is quite an advantage for some field of engineering where the specialists are not programmers.
SCADE is an example of a successful industrial product that use synchronous programming: http://www.esterel-technologies.com/products/scade-suite/ (it is actually more based on Lustre despite the company being called Esterel Technologies).
My internship report, which contains a few snippets of Lustre code, is here if anyone is interested: https://pablo.rauzy.name/research/undergrad/verimag.pdf
Internship defense slides: https://pablo.rauzy.name/research/undergrad/verimag-slides.p... (ewww these colors… sorry for what 2010 me did with that).