I feel the need to ramble slightly OT on how great Lua is: I was looking for an architecture/tech stack recently that would allow me to develop a cross-platform desktop GUI.
I went on a several-weeks-long fact finding mission (the longest of its kind I've ever done in my 10 years as a professional software developer).
The option that won was to write all business logic (a few thousand lines of code) in Lua, then write the GUI in each platform's native language+ui-library combination and re-use the same business logic by embedding Lua.
Another option that made the shortlist was using Haxe instead of Lua, but after several weeks of active Haxe development, it became clear that that was a bad idea, and with Lua, the developer experience is now so much better.
I definitely plan on continuing to use Lua as my main programming language.
This comes after 20 years of having python as my main programming language because I'm displeased with feature creep and bloat on python. With lua, I find that I barely miss any features/abilities from the vastly more complex python while the simplicity of lua means my code gets to "go places" where python can't go.
With lua, you find casual implementers making fully compatible alternative implementations (e.g. NeoLua for C#, Luna for Java, fengari for JavaScript, ...) With Python, alternative implementations seemingly just can't keep up with the pace at which CPython is introducing unnecessary new features and CPython-compatbility is de-facto the only meaningful python standard there is. Jython and IronPython would make the platform so much more appealing, but they appear dead in the water. Python implementations for the browser pop up every couple of years only to see little adoption and quietly disappear again.
What's more: Once you've settled on Lua as an embedding language, developers of Lua logic are free to use not just Lua, but they can pick from a host of cool transpile-to-Lua languages [1].
I guess you have already tried it but if not: there is the iup lua library which use native toolkit on windows and gtk on Linux. https://www.tecgraf.puc-rio.br/iup/
Also I would be happy if you briefly describe the problems you had with haxe.
I looked into JS as an alternative, given that ES6 cleaned up a lot of the things that had previously been bugging me about JS. I thought JS must be well-suited for embedding usecases, and the vastly larger language community, compared to Lua, must be an advantage of some sort.
But I ended up concluding that I still don't want to go anywhere near JS.
It's like browser-based use of JS and node-based use of JS are sucking the air away from JS's potential as a language for embedding.
e.g. Nashorn was part of the Java standard API in Java 8 but then got dropped. There's project Detroit to try to replace it, but it doesn't seem to be going anywhere. Most people interested in embedding JS in Java will presumably want node compatibility, even though node is not a great architecture for embedding, so that's what GraalJS is doing, but it comes at the cost of a loss of portability to non-Graal Java environments. A widely-used way of embedding JS in C# is by actually invoking the system browser through WebView in some weird and convoluted way. ...it's things like that which make me recoil in horror. Meanwhile Lua for Java and Lua for C# is just quietly and humbly in existence and using a sane architecture.
...and then JS libraries are full of this async-stuff with promises and whatnot, and I'm reluctant to go anywhere near that if I'm positively certain that it serves absolutely no purpose in the applications I actually intend to build and comes at the price of making code so much more complicated and unreadable.
I think your reasoning makes total sense and agree with the criticisms of the JS ecosystem. Just to throw out an alternative embedded-JS option for you or anyone else looking to do something similar though, there’s QuickJS from Fabrice Bellard (author of ffmpeg and more) which seems to have a very Lua-like vibe to it in terms of intended use.
Only used it for throwaway/toy code myself, but it’s been a generally pleasant and frictionless experience.
Can you elaborate on what it is you find unmanageable about Lua at scale? Is it just typing that you're missing?
The biggest difference between Lua and TypeScript in my mind is that Lua has been going on a minimally-invasive and continuous upgrade path for decades, so I assume that it will likely keep doing that for several more decades. With TypeScript I can't tell whether it's here to stay or just this week's iteration of CoffeeScript on the JS fashion treadmill.
That may be less of a consideration for more ephemeral types of applications like websites and games, but it becomes a huge consideration for applications that require large spans of time to ammortize the cost of building them like individual software in the corporate space or applications that are somehow highly specialized. (This is the area that I'm in).
I want to like Teal, but the lack of nil checks[1] is a pretty big sacrifice in the name of "staying true to Lua idioms".
>>> Every type in Teal accepts nil as a valid value, even if, like in Lua, attempting to use it with some operations would cause a runtime error, so be aware!
I know you can use (or implement your own in about 8 lines) strict.lua[2], but that just seems like such a shame to omit nil checks from a gradual type system. I still follow the project, but I put a little more hope in Pallene's[3] development, although the aims are slightly different.
Haxe is great for when you want to write an entire application in Haxe, then transpile to multiple targets, and then care about the target platform only to the extent that you want your application to just work.
The various haxe game engines are a good example of this kind of use case, where they transpile your haxe code to C++ or JavaScript and then your transpiled code combines with JavaScript code that the game engine provides or with C++ code that the game engine provides and the result is that everything "just works", both natively and in the browser.
I also have high hopes for this approach in relation to GUI programming (HaxeUI, FeathersUI, etc. are very interesting).
But my usecase was different: I wanted to make an API for my business logic that would transpile to Python, JavaScript and Java, and give a developer on each target platform a native look and feel, as if they were interacting with a native Python API or Java API, etc.
Basically, when you do that, you'll discover that Haxe is too much of a leaky abstraction.
For example when your API requires passing an iterator over Strings or returns an iterator over Strings, you'll discover that this doesn't automagically turn into java.util.Iterator<String> when you transpile to Java. Rather Haxe has its own implementation (haxe.Iterator) that transpiles to some weird Java object that a Java developer will have a difficult time interacting with. ...this is true not just for iterators but for a lot of very basic things like collections, exceptions, etc.
Haxe does expose target-specific things on the Haxe-side, so you can write Haxe code that will accept java.util.Iterator or return java.util.Iterator, but, obviously, java.util.Iterator will not be available when you try to transpile to something other than Java. So whenever you want to just use an iterator, your code is going to be full of "if this platform then behave like x, if that platform then behave like y, ..."
Outside of development around the main Haxe-based game engines, you'll also find that the community is just too thin to properly maintain libraries. For example, several libraries that implement very basic things haven't been touched in years and I discovered that the HashMap implementation in the Haxe standard library is just broken and no one seems to care or notice. It just doesn't handle collisions [1]. ...the only way I can explain that to myself is by assuming that there just aren't enough people using HashMaps on Haxe directly, because the game engines or target platforms provide something else that displaces that functionality or that games are just the kinds of applications where the errors that result from hash collisions aren't noticeable. The advice I got from a seasoned Haxe veteran regarding libraries was to not use haxelib and dependencies at all but instead copy & paste the library code I really needed, fighting hard to keep that to a minimum, and maintain it myself.
It's a pity, because the Haxe language is great, and the ideas behind the architecture are great, but the current implementation IMO just hasn't yet made enough progress on the journey it embarked upon for Haxe to be an option yet for major investments in any non-game software development.
The option that won was to write all business logic (a few thousand lines of code) in Lua, then write the GUI in each platform's native language+ui-library combination and re-use the same business logic by embedding Lua.
Another option that made the shortlist was using Haxe instead of Lua, but after several weeks of active Haxe development, it became clear that that was a bad idea, and with Lua, the developer experience is now so much better.
I definitely plan on continuing to use Lua as my main programming language.
This comes after 20 years of having python as my main programming language because I'm displeased with feature creep and bloat on python. With lua, I find that I barely miss any features/abilities from the vastly more complex python while the simplicity of lua means my code gets to "go places" where python can't go.
With lua, you find casual implementers making fully compatible alternative implementations (e.g. NeoLua for C#, Luna for Java, fengari for JavaScript, ...) With Python, alternative implementations seemingly just can't keep up with the pace at which CPython is introducing unnecessary new features and CPython-compatbility is de-facto the only meaningful python standard there is. Jython and IronPython would make the platform so much more appealing, but they appear dead in the water. Python implementations for the browser pop up every couple of years only to see little adoption and quietly disappear again.
What's more: Once you've settled on Lua as an embedding language, developers of Lua logic are free to use not just Lua, but they can pick from a host of cool transpile-to-Lua languages [1].
[1] https://github.com/hengestone/lua-languages