Golua – A Lua 5.3 engine implemented in Go
github.com
github.com
And they just released an Azure Go SDK earlier this year.
How go and lua fit into their product line I'm less sure of.
Looking at the VM, they implement function calls by recursively re-entering the VM in Go. The VM implements neither tail calls nor coroutines, and I don't see how they could implement the latter without some serious refactoring.
Perhaps by adding a debugger they mean they implemented the VM such that they could repurpose existing Go debuggers, which is why there's a 1:1 mapping between the Lua call chain and the Go runtime call chain.
I expect more docs, details, and improvements will be coming
Better debugging is one of the big things holding Lua back, IMHO.
Lua's stack protocol can sometimes be verbose, but I find it infinitely more simple and elegant than the existing alternatives.
I think you tend to see long, unwieldy code blocks that invoke Lua functions multiple times because you can, despite how tricky it can be to track the top of your stack. You rarely see this in Perl or Python because it becomes impossible to manage long before that point. So the solution for Lua is the same as for other interfaces--use shorter, simpler functions and compose them. This is usually easier and more performant to do in Lua, anyhow, because there's less fixed boiler plate and indirection necessary; not to mention Lua gives you many more facilities for stashing and managing your C state across calls (like closure upvalues, userdata values, continuation context cookies, etc) without resorting to global variables either inside or outside the VM.
table := lua.MakeTable()
table.Set(lua.MakeString("five"), lua.MakeNumber(5))
Rather than manipulating values on the stack. But it's possible there are reasons for not doing that that I'm unaware of. Was just curious. lua_pushstring(L, "five");
lua_pushnumber(L, 5);
The above is shorter and also significantly more efficient because you're not creating the intermediate table object. Even in Go, given Lua's coroutine and tailcall semantics (assuming they were implemented) the Go compiler would likely be forced to always heap allocate the argument list table. There's a reason PUC Lua is blazingly fast, and its partly the same reason why LuaJIT is so fast--the Lua stack protocol is a thin abstraction that easily admits a simple, efficient implementation yet still managing to provide an effective interface boundary that doesn't leak (beyond the fact of the protocol itself).I don't think there's any good middle ground here. The best options are (1) Lua's explicit stack protocol or (2) some sort of type inference that permitted a direct call, like lua_tcall(L, "five", 5), into the VM. You can actually implement the latter in C somewhat easily (at least if you stick to simple data types) by using _Generic and __VA_ARG__ macros to generate the stack pushing code.
But I rarely see this done because it's a lot of magic for little gain. And where I have seen it done it's always been annoying because it's too leaky--invariably you have to fallback to the stack pushing code because there's a limit to the types of automagic type coercions you can accomplish between two drastically different languages. So you have to learn their magical wrapper routines in addition to the regular Lua API.
Many years ago I abused __VA_ARG__, __builtin_types_compatible_p, and libffi so I could invoke ad hoc functions as libevent callbacks without having to proxy the call through a function that unwrapped a pointer-to-void cookie. See http://25thandclement.com/~william/projects/delegate.c.html I still think it's kinda clever but I can't remember the last time I actually used it. Even in code bases already using delegate.c I ended up returning to the slightly more repetitive but transparent and idiomatic patterns for installing libevent events.
lua_newtable(L);
lua_pushstring(L, "five");
lua_pushnumber(L, 5);
lua_settable(L, -3); lua_newtable(L);
luaL_setfieldi(L, -1, "five", 5);
rather than having to roll your own. Part of the function of the stack protocol is to minimize the number of unique functions needed to load and store values across language boundaries. So there's a single [low-level] function for communicating a number value in a type-safe manner, rather than a multitude of functions--one routine for setting a number value for a table string key, another for a number value for a table number key, another for a string value for a table number key, etc. The permutations explode, and unless the host language has some sort of generics capability then it adds significant complexity both to the interface and to implementation maintenance. (See Perl XS.) Alternatively you can reduce the number of permuted interfaces by using printf-style formatting strings and va_lists, but that's not type safe. (See Py_BuildValue.)Notably, Lua 5.3 removed lua_pushunsigned, lua_tounsigned, luaL_checkint, luaL_checklong, and many similar routines as there was never an end to the number of precomposed type coercing, constraint checking auxiliary routines people demanded. They decided that the only way to win that game was to not play at all. But with C11 _Generic and a dash of compiler extension magic you can actually implement a richer set of type agnostic (but type safe) numeric load/store interfaces in just a handful of auxiliary routines. For better or worse, though, Lua doesn't target C11 nor wish to depend on compiler extensions. "Batteries not included" is a whole 'nother debate in the Lua universe.
This. TL;DNR, used a C/Lua binding to explain the Lua stack to a fellow engineer. Took a few post-it notes to keep track of 4 levels of stack, 1 pcall back to Lua to sort an array, and forward the results on. It just worked, was elegant, and blew our minds.
Today on Friday at 5pm I was talking about a ‘problem’ we had with a Lua daemons compared to their C brothers. Due to the use of tables, each time you queried them, the output order was always random. Computers don’t care, but a big user is also engineers and finding fields wandering all over the place is a pita. So what if we ordered the keys alphabetically instead? The code is Lua -> C -> IPC -> Output. The order is set in the Lua->C binding, so what if we sorted it in the binding.
But the tables are arbitrary size and you’d have to allocate memory, put them in a structure of some kind, etc, etc. Then we realized we could just put all the keys in a Lua array, and sort them with table.sort(). We could then use the array to get key/values in order, all from within the C binding.
Being late Friday, and having talked it through let’s just do it. Plus it was a handy teaching moment to explain to a fellow engineer how Lua binding worked, including a call back into Lua. By 6pm we had the binding recompiled, tested and it’s just worked.
Lessons learned:
1. The stack can seem confusing, but once you learn how to work with it, it’s pretty amazing.
2. The Lua reference docs are amazing. They clearly list what they pop and what they push onto the stack.
3. Calling back into Lua is.
4. It looks like write only code. Reading the code needs a post it note to keep track of the stack, along with the Lua reference manual. -- comments...
Dear God, the suspense is killing me!
I don't believe Go has been optimized for compiling an interpreter, so perhaps there is low-hanging fruit, should the Go team decide that it's a priority.
However, to really do as well as C, Go would need a more space-efficient union type. A Go interface is always two pointers due to how the garbage collector works, and that's not going to be as efficient as using something like NaN-encoding for a union between a pointer and a float64.
But if someone else wants to work on it, it might be fun.
This was something I was wondering about with Cloudflares isolate implementation as well. I read that in node/v8 you can inspect an isolates CPU usage, but no way to limit it apparently? If you start out with 1/2 of a CPU but your program gets squeezed down to 1/1000 as more isolates are added or existing isolates use more time you could be in for a big surprise as your program no longer performs adequately, perhaps to the point of not functioning properly at all.
https://github.com/Azure/golua/blob/24b0595f74412f2f249fbdb3...
Isn't this a pure Go implementation?
The function you call emits IR, and it's doc block says:
// EmitIR compiles the Lua script similarly to Compile but instead
// uses the long listing options to capture the compiled IR dump.
// EmitIR returns the Lua bytecode encoded as a string or any error.https://github.com/kyren/rlua/issues/100
https://github.com/kyren/rlua/issues/39
Edits.. Resources found so far:
https://users.rust-lang.org/t/can-rust-interface-with-go-lib...
https://medium.com/learning-the-go-programming-language/call...
https://github.com/softprops/shiplift (okay, here's a Rust interface to Go)
I'd love to see a high-level language like Lua (or Python, Ruby etc.) with good threading support. Building a language runtime in Go might be a good way to get that support more easily?
While I'm wishing for things, could I have good single-threaded performance too? This would likely need a JIT, which unfortunately doesn't seem possible in Go at the moment [0].
Maybe I should give up on my desire for a high-level language and just use Go itself, where concurrency, parallelism and good performance are all available today...
Are we going to see GoPython and GoJS?
> Starlark is a dialect of Python intended for use as a configuration language
Edit: seems there is an open issues for adding some of this https://github.com/Azure/golua/issues/15
I'm amazed people found this already. The team over there who owns this is excellent. I expect it to work nicely once they have had a little time to get everything together.
I think go and rust serve two somewhat different use cases- go being for distributed computing in a nutshell, and rust for fast running programs. And I think Rust would have been a better choice
Edit: looks like everybody and their dog has a Lua engine now- maybe I'll create one in rust
Probably because they wanted to use it from Go?
I can imagine how exposing a Rust API to a non-Rust program could be as problematic as a C++ API: your common denominator is a C API, which adds cumbersomeness and removes (some of) the safety.
> We also wanted clean and idiomatic Go APIs
If you want to use this as a scripting/plugin language for Go programs (say, for those distributed computing programs you mentioned), it's pretty defensible to make it integrate with Go better by... building it in Go.
Then don't.
That's quick and dirty. Dirty, because the way Go's GC is optimized is likely to be very unsuitable for Lua.
If you already have projects in go then a rust project will not be of any use, and vice versa...
Alternatively, while it would be nice to have a Lua engine entirely in Rust, Rust goes to great lengths to make calling into C have no runtime cost, so you generally just see people writing Rust wrappers over the C API, which tend to impose varying degrees of additional safety on top (Lua internally does a ton of setjmp/longjmp, among other things, so it's not easy). A good example of "wrap and add safety" is Chucklefish's wrapper, being used for their game Witchbrook: https://github.com/kyren/rlua
If you are going to say GC, it all comes down to how one designs the respective data structures.
Having done some compiler related work back when we had Caml Light, OCaml was still called Objective Caml and Mirada was being turned into Haskell, I don't see what I would gain from having to deal with the borrow checker.
It's the ADTs that are killer compared to Go.
If we're veering off into hypotheticals that don't have anything to do with the question at hand, I personally write compilers and interpreters in Rust rarher than another ML because my use cases tend to be worst case latency sensitive enough that a GC is a non starter.
I'm a Helm maintainer so I'm familiar with the history of how this came to be.
As Helm so far could operate with a simple template language , and now suddenly jumps to a Turing-complete configuration language - this seems quite large step... What is the justification?
Lua provides the ability to have the language embedded easily (it was designed for that) for use in cross platform situations (Windows included).
Does that help?