Toit, infinite resilient application loops (try “catch”)
Toit is a modern high-level language designed specifically for microcontrollers. I’m spending some time at work making use of it these days, and as it’s a younger language, there are not as many resources out there in comparison to others.
In Toit, you could write a very simple hello world application with the following code…
main:
print "Hello world"
Code language: PHP (php)
Say you wanted to get a new name from an external package to say hello to, you might do the following, which would call the method names.next
, which can return a string, and print it to the user.
import somePackage show names
main:
print "Hello world " + names.next
Code language: JavaScript (javascript)
To do this in a loop every second, your code might look something like this…
import somePackage show names
main:
while true:
print "Hello world " + names.next
sleep --ms=500
Code language: JavaScript (javascript)
If you wanted two separate tasks running with their own control flows, you might make use of tasks, and a second loop.
Here we have one that prints a name every 500ms, and one that prints the time every 1s.
import somePackage show names
main:
task:: loopOne
task:: loopTwo
loopOne:
while true:
print "Hello world " + names.next
sleep --ms=500
loopTwo:
while true:
print "Current time " + Time.now.stringify[11..22]
sleep --s=1
Code language: PHP (php)
If names.next
is the sort of thing that might throw an exception, or crash for some other unknown reason, the state of the app might end up a little wonkey, with loopTwo
continuing to print the time, but loopOne
having crashed.
The whole app started in main
will continue running in this situation.
In order to avoid this and keep the loops restarting in case of any unhandled exception, we can wrap them in a try block.
We can abstract this try block away so that it can be used for as many loops as our application has.
import log
main:
log.info "Application starting"
task:: catchAndRestart "loopOne" (:: loopOne)
task:: catchAndRestart "loopTwo" (:: loopTwo)
log.info "Application started"
catchAndRestart name/string l/Lambda:
while true:
e := catch --trace:
log.info "Running " + name
l.call
if e:
log.error "Caught exception: " + e.stringify
log.info "Restarting " + name
//... Including the same loops as above
Code language: JavaScript (javascript)
I only wrote this little method today, and there might be better ways to achieve it, but right now I quite like it.