[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: How Lua code can be updated at runtime without breaking global state?
- From: Jean-Luc Jumpertz <jean-luc@...>
- Date: Tue, 26 Mar 2013 09:56:39 +0100
Hi,
> I periodically find Lua-based projects that do "dynamic update" (one of them - Celedev - was announced on this list less than a day ago with a great video :)). These projects update code in runtime while application is still running.
>
> I am wondering, what techniques are used to dynamically update Lua code without breaking normal execution of a program?
>
Updating Lua code without breaking normal execution of a program is clearly possible with Lua and we do it in Celedev as you have seen in the video. :)
However you can not just take any piece of code and declare it dynamic. This requires the running program to be written with a small number of simple design rules in mind, to enable the dynamic update to go smoothly.
First let's start with the great feature of Lua that makes all this possible: as written in the doc "functions in Lua are first-class citizen".
This means that when you reload a code chunk, functions created in former versions of the same source file will continue to exist in the VM until they are removed by the Garbage Collector. The same is true for the code chunk itself that Lua considers as an anonymous function.
The practical consequence of it is that, if you reload a code chunk while a function is running, the execution of this function will continue undisrupted until it returns, and - if the code is designed for dynamic update - the new version of the function will be run the next time the function is called.
Well. That's the basic idea behind dynamic code update (at least as we have implemented it at Celedev).
Now what are the design principles for a dynamic-update-compliant code?
There are, as always, various approaches to solve this problem. Here are the main design rules I have chosen for Celedev:
(please, no trolling / philosophical off-topic on these ;)
1 - Use Object-Oriented design everywhere
With an appropriate OO framework, one with separate classes and instances, a method (stored in a class) can be replaced without impacting the instances of this class. Thus you preserve the application's object graph (the data) while updating the application's behavior (the functions).
For Celedev we have designed our own OO framework so dynamic update works as transparently as possible. Like all other object frameworks in Lua, it is based on tables and metatables.
2 - Use no more global variables than strictly necessary
Regardless of the dynamic update aspects, this is always a good rule of thumb. For dynamic code update, an additional rule is: avoid recreating globals unless you know what you are doing. ;)
This can be implemented - as previously mentioned by Vadim - as a single-line instruction like: variable = variable or default
or when you need a more complex init sequence you can you can use a if statement like : if variable == nil then --[[ init variable]] end
3 - Don't use upvalues for storing persistent state information of the program
Because upvalues are references to local variables and are recreated each time a code chunk is reloaded, they can not be used for memorizing program state data.
This will not be an issue if you comply to "1 - Use Object-Oriented design everywhere" and have your program state data stored in your program's obects graph.
Of course this doesn't prevent to use upvalues heavily for other usages!
Hope this clarifies the magic behind dynamic code update.
Jean-Luc