Lever's Eventloop
I had an error in configuration that caused issues with getting RPython stacklets to work properly. It took 3 days to figure out what was wrong. That won't make the working eventloop any less satisfying though. Anyway, there are several new commands such as: schedule(continuable, arguments...)
, sleep(duration, continuable)
, time()
If you have never read about Lever, you may want to read the last week blogpost or peek into the leverlanguage.com -website.
Lever has a built-in event loop that shares characteristics with javascript's event loop. The difference is that Lever associates greenlets for events instead of functions. The greenlet is a form of a continuation.
Before you wonder what's a continuation, lets look at a Lever code sample, as how I will introduce it just before the year changes!
# This code is in samples/ticktock.lc in its current form.
main = ():
print ("hello from main")
schedule(tick_tock)
sleep(1.0)
print ("hello hello")
sleep(1.0)
print ("hello again")
sleep(1.0)
print ("and bye")
tick_tock = ():
i = 0
while i < 3
print("tick")
sleep(0.5)
print("tock")
sleep(0.5)
i = i + 1
This program will print:
hello from main
tick
tock
hello hello
tick
tock
hello again
tick
tock
and bye
The program does exactly what it appears to be doing. I decided to omit the javascript version of this program to preserve sanity of the reader. I can tell you it contains lot more than two functions.
What is happening here is:
schedule(tick_tock)
constructs a greenlet that calls tick_tock(), and immediately enqueues it into the event queue so it runs next time when the control is returned to the event loop.- Then
sleep(1.0)
puts the current greenlet to sleep for a second and drops the control to the event loop. - The event loop switches to running
tick_tock()
, which also sleeps after printing into the terminal. - At this point both greenlets are sleeping, so the eventloop puts the whole thread to sleep until either of the slept greenlets have slept the intended amount.
Compatibility with callbacks
You may wonder whether you can still wait in the javascript-style. It's entirely possible: The sleep can be also applied to a function or different greenlet. In that case it won't return to the eventloop. You give the function as an extra argument: sleep(1.0, tick_tock)
.
Overall the greenlets are mostly accessible from within the language, so you can mix greenlets and ordinary callbacks just fine as long as you understand what you're doing.
Continuation
In Lever's terms, continuation/continulet is an extended form of a function call. This call can decide where it returns. Activating a continuation is called "switching". The mechanism forms the basis for concurrency in Lever.
Continuation is a bit like haunted mirror: Whenever a continuation is switched upon, an execution is released and the current execution takes it's place in the continuation.
Greenlets
Those continuations are perfect way to implement this behavior, but as a language construct the continulet doesn't tell where to return if an error occurs. Here greenlets come to be helpful: Greenlets describe where they return to, and form a sequence of returns back to the root greenlet, which is the event loop in our case.
When greenlets switch, the current greenlet takes the container for continuations from the target greenlet, sets the target greenlet as current, then switches into it. The result is that the previous execution of the previous greenlet is now suspended and the target greenlet is recovered.
Cutting edge
Greenlets can be used to write completely untractable code. Similarly you can attach pair of chainsaws into a steel chain and get chainsaw nunchucks.
Lever submits to the idea that proper language constructs are meant to be powerful enough to be capable of harming their user when abused. They are provided in convenient forms that do not encourage wrong use, but are perfectly unable to prevent the user from being utterly stupid. This is done to encourage cleverness, as there is very thin line between the two.