I think that makes it the second (production-ready) language to have a primarily-structural type system, after TypeScript/Flow(/and Closure to some extent) for JS. I wonder if it will follow in their impressive footsteps or if it will tread new territory.
One of the things that Flow gets right that TypeScript doesn't yet support is switching to nominal type-checking between class instances. In TypeScript you can assign an instance of one class to an instance of another as long as they have compatible fields. Compare:
TypeScript doesn't have any understanding of prototypes or prototypal inheritance, which is a big gap considering that it's a fundamental aspect of JS.
I'm really hoping Luau will come to do the right thing with tables and prototypes. Perhaps it already does, but unfortunately there doesn't seem to be a Luau playground to try in the browser.
Luau already has some notion of nominal types to deal with the fact that the Roblox API is basically a ton of C++ classes that have been mapped over via the FFI. Some of these types are totally structurally identical and yet incompatible.
We'd like to afford the same kind of ideas for native Luau code, but we're not there yet.
Super happy to see this released, and also for all the kids getting started programming on Roblox learning that there is a better way than random tag-checked mush :-)
Good on you all!
A regular MOVE is sort-of structural. It moves field i of the source to field i of the destination. Source and destination need not be of the same type, though.
MOVE CORRESPONDING is nominal. It moves field Foo of the source to field Foo of the destination (leaving fields that do not have corresponding items alone)
In both cases, data may be converted, for example from alphabetic to alphanumeric.
Funny that you would mention that in a thread on a statically-typed language based on Lua. Don't you need some insane mechanism to be flexible at runtime anyways? Either it will be reflection, or something like prototypes (in OO languages).
I think OCaml isn't just structural. For example, sum types (variants in OCaml) have a nominal form which is the default: https://ocaml.org/manual/coreexamples.html#s%3Atut-recvarian..., but also a structural form, polymorphic variants: https://ocaml.org/manual/polyvariant.html. I think it's the same for records, I didn't find a way to express the type "a record that has a certain field" as an argument of a function. You can do this with objects and modules I think, but not with records.
I forgot about OCaml (since I normally associate it with the more sophisticated typing stuff). I don't know if I'd completely count Go since interfaces only apply to methods, not fields
I was thinking of how you can embed types in structs. You automatically dereference the fields and methods of the components directly from the outside.
Yep, in go the inheritance (using the term loosely) structure can apply to interfaces (which specify groups of functions) and structs (which specify groups of data) and roughly does the same thing in both instances.
> In TypeScript you can assign an instance of one class to an instance of another as long as they have compatible fields.
Fun fact: If you add a private field to a class it'll behave nominally in TS. This is because private fields kinda require nominal relations to function. So, in a way, it does support "switching" to nominal type checking for classes - the opt in is simply per-class.
But variance depends on position where the value is used, not at the time of declaration, superclass/subclass at parameter/return value position can't be correctly encoded like this, can it?
I think most languages define variance at type definition level, notable exceptions being Kotlin which supports both [0][1] and Flow. But yeah, TS doesn't support (variable-)declaration-site variance which I didn't realize you were asking in my previous answer.
I'm less familiar with OCaml and don't know off the top of my head. Doing a quick search I was only able to find references to type declaration variance [0], though I learned that Java also supports use-site variance too [1]
If any of the Luau devs are watching this, please flesh out the metamethods. I'd switch almost everything to Luau if they were improved.
They're the biggest PITA right now as designed in PUC-Rio, and I see that while you've improved upon __eq, other metamethods are still lacking.
In PUC-Rio, boolean equality operators FORCE a boolean result, regardless of what you return. Ideally they would allow returning any result type, which then can be coerced to boolean later (e.g. by an `if` statement), just like the arithmetic operators do.
Further, `__neq`, `__ge` and `__gt` do not exist. They should.
The lack of a proper metamethod design means that binding to e.g. Kiwi[0] is impossible without some incredibly fugly hacks. It has been a long-standing annoyance with Lua in an otherwise beautiful little scripting language (that I use frequently).
This looks quite nice - lots of attempts in this space but nothing that attempts to match Lua to this degree.
You still don’t need `>` for any of those examples though, do you? For example, `NULL > 1` could be rewritten as `1 < NULL` (even though it can’t be rewritten as `not(NULL <= 1)`.
It compiles down to lua, and really beefs everything up. Interface is super nice too. You just put `require "moonscript"` at the top of the file and you're done, now just write your code in moon script.
To my understanding it’s not so much a fork of Lua as it is a complete rewrite in C++. They’ve created their own custom VM and everything. The closest version it has parity with is Lua 5.1.4, with a few compatible features from 5.2 and 5.3 backported.
PUC-Rio's Lua doesn't take contributions anyway, right? It's open source but it's not an open project. Similar to.. uh.. nethack, at least how it used to be :)
Everybody's focusing on the type stuff, which is nice -- but luau also just performance better than Lua in a bunch of cases.
Arseny (from Roblox) has tweeted a bit about it. It's interesting to follow!
Can this transpile type-annotated Luau code to just regular Lua code? I would like to add type checks to my Lua code but I dont want to run it in the Luau VM. I want to run it in PUC-Rio Lua, and LuaJIT. Something like Haxe[1], but not an entirely different programming language.
There is a transpiler in the source tree, but I expect it needs a polish pass. We haven't put it to use in quite some time.
In particular, I am pretty sure that it won't do the right thing when it encounters the extra syntax we've added to Luau. So far, that's an if-else expression and a continue keyword. Transpiling those accurately will take a bit of work.
> using a combination of techniques pioneered by LuaJIT and custom optimizations that are able to improve performance by taking control over the entire stack (language, compiler, interpreter, virtual machine), we’re able to get close to LuaJIT interpreter performance while using C as an implementation language.
At first I was a bit surprised by this, given that they have much better type information, but they forget to mention until further on that Luau doesn't use JIT/AOT optimizations (yet). Still, it's as good an excuse as any to bring out this quote again:
“LuaJIT is much faster than all of the other languages, including Wren, because Mike Pall is a robot from the future”
Slight digression. IIRC PHP was using Mike’s work (DynASM) a while ago. Is this still the case and is anyone else using aspects of LuaJIT (eg DynASM or the byte code interpreter)?
People seem to say this (or similar remarks) when talking about Lua but even more specifically, LuaJIT in particular but it seems like Lua is already a pretty niche language so am I just missing something? Like you can embed Lua in other languages but why use Lua instead of something like mruby for all the warm fuzzy feelings you get when writing Ruby?
Just curious, appreciate any context you can provide!
The main reason is momentum - Lua has been the de-facto standard embeddable language for at least 15 years. For example, it's used in World of Warcraft which was released in 2004.
Another reason is the quality of the implementation - Lua has very few bugs [0], whereas Shopify tried to embed mruby and had to give up because it had too many security holes [1].
Finally, Lua is a complete language in itself, with a guidebook, reference manual and so on. Mruby (and MicroPython) are less well-known. Plenty of people know Ruby or Python, but if you use the smaller implementations, you never know when your code might hit a language feature that they don't support.
The advantage that Lua has is that it has about the simplest possible binding interface you can imagine for a Language.
There's no manifests, no class definitions, no anything really. It's as simple as calling lua_newstate to create a state, calling lua_pushcfunction to register some functions that expose your desired engine functionality, and calling lua_loadstring with a script to run.
That means you can use Lua in your engine for something as simple as a CLI interface that just exposes a couple dozen functions, and it's still worth it. Where with any other scripting language you'd have to be doing a lot more with it to make the setup cost worthwhile.
Having LuaJIT available if you end up wanting to do more with it later is the icing on the cake.
> it seems like Lua is already a pretty niche language
Keep in mind that what we see on the internet is a vocal publicly part. Some important domains are not publicly represented.
For example, in my domain CGI/VFX, Python is used all around, but lua has growth in some places. For example it is used in Guerilla[0] and Katana[1], two software related to rendering and scene management. Technically a niche, but commercial product too. So, groups of people uses it all day but you will not find questions about it on stack overflow.
The reason to choose lua despite having Python all around is it's lightweight, apps can hack the VM for your specific needs, function call cost is faster and you can easily expand it with C (compared to Python).
This is just an example related to my domain, but I suspect this pattern is similar in many domains that doesn't pop on the internet. I suspect web dev is overexposed on the internet, making people thinking it's how dev runs all around.
There is a language [1] that type check by adding comments instead of fixing Lua (like Flow comment syntax [2]), I wonder if the Luau team has considered this language.
I can recommend reading the performance page, it's a an engaging summary of the various tricks/optimisations that have been implemented https://luau-lang.org/performance
The first thing you do is to play - and one day you play on a computer.
And here it is you learn it all.
How to operate a OS and what to expect of it.
How to install a program.
And how to program.
Which means in 15 years, lua like syntax will push aside java-script, because this generation learned it in another way. Might aswell embrace it ahead of time.
Learned Future Preference dominance is gaming market dominance.
Lua's biggest thing is that it's pretty easy to embed inside a C/C++ application safely, for relative definitions of "safe" spanning "preventing the Lua code from segfaulting your application" to "preventing the Lua code from doing anything you don't explicitly give it the ability to do".
It's why you see it used as so many game's plugin architecture and why it was selected for NeoVim.
So there is a very large ecosystem of Lua code that just lives in Lua 5.1 and doesn't really push forward at all. I haven't checked in on the situation for some time, but most people who write Lua are writing Lua for something like NeoVim or WoW or some other plugin for a larger project. Those projects have no interest in dealing with the slow reference VM for Lua >=5.2 at this time.
Lua 5.2, 5.3, and 5.4 are more analogous to Python 2 to Python 3's level of change, rather than Python 3.9 to Python 3.10. These more recent versions of Lua 5.x are somewhat incompatible with each other, rather than just adding new language features.
Most products settle on Lua 5.1 because that is what luajit, a very fast just in time compiling implementation of the Lua VM supports. Plans to further support to new versions for luajit are...well they exist.
> WoW [...] have no interest in dealing with the slow reference VM
Does WoW use LuaJIT? I thought it used the reference Lua 5.1 VM, simply because that was the newest version when it was first released.
> Plans to further support to new versions for luajit are...well they exist.
I’m not sure it’ll ever happen. AFAICT LuaJIT is so complex that only its author, Mike Pall, understands it well enough to make major changes. He has expressed his dislike for several of the changes in Lua >= 5.2.
> Does WoW use LuaJIT? I thought it used the reference Lua 5.1 VM, simply because that was the newest version when it was first released.
I didn’t mean to imply WoW was using luajit, apologies. I was under the impression that over the years they have patched and fussed with code of the reference VM to resolve some performance pain points in the vanilla UI lua. Unfortunately, I can’t find the source for that.
Regardless, I’ve always assumed that they had little interest in both rewriting their vanilla UI to newer versions AND starting over from square one trying to resolve any performance hiccups they hit.
I can tell you from my own experience that luajit, which also targets 5.1 compatibility, is _significantly_ faster than Lua proper. In using it I've never missed 5.2+ features. So I imagine luau has the same thing going for it.
True, but they claim to have gotten as fast as LuaJIT in many cases and, important for their use case, JIT doesn't work on some platforms (iOS): https://luau-lang.org/performance
> On some workloads it can match the performance of LuaJIT interpreter which is written in highly specialized assembly.
Note how it says: "match the performance of the LuaJIT interpreter" (emphasis mine).
LuaJIT basically has two parts: an interpreter in handcrafted assembly which is quite a bit faster than the standard Lua VM, and the actual JIT, which is even faster. IIRC on iOS the JIT is not allowed but the interpreter is still there.
Lua 5, unlike other foobars, is a complete language from the start. You may see 5.x as 5.a, 5.b, 5.c and so on rather than as “evolution” versions. The second digit is more like flavor, and as e.g. 5.2 or LuaJIT user you don’t miss 5.4 features. Moreover, some people, me included, find some of 5.2, 5.3 and 5.4 experiments questionable.
Why is it so? Usually, when a language unlike Lua “evolves”, it just lacks a flipping lot of core/meta features from the beginning, crutch-adding them later. So users long for 1.x+ version so much, because 1.x is still bullshit, for any x. In case of Lua, its 5.1 version had some flaws, but it already had (arguably) more powerful execution/data model-wise than e.g. python or js, and these flaws were related to what the latter two haven’t had at all (because to them Lua is Lisp, in a sense of blub paradox). Coroutines, environments, metamethods, etc. 5.2 solved all of the remaining problems one way, LuaJIT another way. Upgrading to >5.2 doesn’t really change much in a way it works, but it’s enough to break your existing codebase.
So, “especially now” doesn’t have much weight in this case.
Thank you for this. I kept trying to pronounce this as some combination of "lua" and a "u" sound, which made no kind of sense. I have apparently never seen the word "luau" out of context.
Not according to their own front page: "Luau (lowercase u, /ˈlu.aʊ/)". It would also be very unlikely, because it would make it different from the usual pronunciation of the word "luau" [1], which it seems to be making a pun with.
What is it with grafting type systems onto dynamic, interpreted languages? Can't we just leave them alone? There are plenty of statically-typed languages if types are required.
Because as codebases in dynamic languages grow and age the developers start seeing the advantages having a static type system to lean on would give them.
the only statically typed language that’s usable with roblox is roblox-ts pretty much, and that’s just an unofficial project that compiled ts to luau. there’s nothing wrong with adding types to luau.
> Luau’s type system is structural by default
I think that makes it the second (production-ready) language to have a primarily-structural type system, after TypeScript/Flow(/and Closure to some extent) for JS. I wonder if it will follow in their impressive footsteps or if it will tread new territory.
One of the things that Flow gets right that TypeScript doesn't yet support is switching to nominal type-checking between class instances. In TypeScript you can assign an instance of one class to an instance of another as long as they have compatible fields. Compare:
Flow: https://bit.ly/3jZx4rB
TS: https://tsplay.dev/mZaL1N
TypeScript doesn't have any understanding of prototypes or prototypal inheritance, which is a big gap considering that it's a fundamental aspect of JS.
I'm really hoping Luau will come to do the right thing with tables and prototypes. Perhaps it already does, but unfortunately there doesn't seem to be a Luau playground to try in the browser.