Luau Recap: March 2021

WARNING: An earlier version of this post introduced a new type checking feature, generic functions. Unfortunately we found a few critical bugs in that feature and had to disable it. Expect it to resurface in the next recap!

Luau is our new language that you can read more about at Luau - Luau. It’s been a busy month in Luau!

Here’s what’s new:

Typed variadics

Luau supports variadic functions, meaning ones which can take a variable number of arguments (varargs!) but previously there was no way to specify their type. Now you can!

function f(x: string, ...: number)
f("lo", 5, 27)

This function takes a string, plus as many numbers as you like, but if you try calling it with anything else, you’ll get a type error, for example f("oh", true) gives an error “Type boolean could not be converted into number

Variadics can be used in function declarations, and function types, for example

type T = {
  sum: (...number) -> number
function f(x: T)
  print(x.sum(1, 2, 3))

Typechecking improvements

We’ve made various improvements to the Luau typechecker:

  • Check bodies of methods whose self has type any
  • More precise types for debug.* methods
  • Mutually dependent type aliases are now handled correctly

Performance improvements

We are continuing to squeeze the performance out of all sorts of possible code; this is an ongoing process and we have many improvements in the pipeline, big and small. These are the changes that are already live:

  • Significantly optimized non-variadic function calls, improving performance by up to 10% on call-heavy benchmarks
  • Improve performance of math.clamp , math.sign and math.round by 2.3x, 2x and 1.6x respectively
  • Optimized coroutine.resume with ~10% gains on coroutine-heavy benchmarks
  • Equality comparisons are now a bit faster when comparing to constants, including nil ; this makes some benchmarks 2-3% faster
  • Calls to builtin functions like math.abs or bit32.rrotate are now significantly faster in some cases, e.g. this makes SHA256 benchmark 25% faster
  • rawset , rawget , rawequal and 2-argument table.insert are now 40-50% faster; notably, table.insert(t, v) is now faster than t[#t+1]=v

Note that we work off a set of benchmarks that we consider representative of the wide gamut of code that runs on Luau. If you have code that you think should be running faster, never hesitate to open a feature request / bug report on Roblox Developer Forum!

Debugger improvements

We continue to improve our Luau debugger and we have added a new feature to help with coroutine call debugging. The call stack that is being displayed while stopped inside a coroutine frame will display the chain of threads that have called it.



We have restored the ability to break on all errors inside the scripts. This is useful in cases where you need to track the location and state of an error that is triggered inside ‘pcall’. For example, when the error that’s triggered is not the one you expected.

"Break on all exceptions"

Library changes

  • Added the function which allows retrieving information about stack frames or functions; similarly to debug.getinfo from Lua, this accepts an options string that must consist of characters slnfa ; unlike Lua that returns a table, the function returns all requested values one after another to improve performance.

New logo

Luau now has a shiny new logo!

Coming soon…

  • Generic variadics!
  • Native Vector3 math with dramatic performance improvements!
  • Better tools for memory analysis!
  • Better treatment of cyclic requires during type checking!
  • Better type refinements including nil-ability checks, and / or and IsA !

This topic was automatically opened after 16 minutes.

Luau open source confirmed?

To be honest, an open-source version of Luau would be amazing. I already love the language and bringing it to a non-Roblox environment is useful for developers like me who also like to write backend code that works with Roblox APIs. Soon all my Roblox stuff can be done in a single language.


Honestly, that new logo could use some work. I’m not getting any Roblox vibes from it. There’s no gradient or box in the middle. :slightly_frowning_face:


Was the U supposed to be lowercased? But yeah It looks good lol!



What will these “better tools” look like, and when can we expect to see these released. Since i think many of us on the forums have expressed our concern about the current tools for memory analysis on roblox will this finally quench our thirst?


The u is intended to be lowercased since Luau is meant to be pronounced the same way as the Hawaiian lūʻau (also spelled luau) AFAIK.


thanks for the PascalCas’ed :grinning: :grinning:




:grimacing: Time to switch all instances of table[#table+1]=value in my code to use table.insert now
Nevertheless, this is a nice change and will definitely make it easier to write easy-to-read code while still maintaining performance!


Time to update some code! This is great, especially when dealing with large arrays of data.

It’s great to keep seeing improvements being squeezed out built-ins, can’t wait to see what’s in store for the future.


Luau looks really confusing on these screenshots
will old games break because of this script update?


Luau is additive: It only adds additional features to the language. Your normal Lua code will continue to work like it did before if you choose not to use the additional Luau features.


How can I use type-checking? I don’t see any changes when running code.


Here is what I think the Luau logo should be:


So it looks more similar to the Studio logo


The Luau Type Checker doesn’t change anything when running the code, it’s a script editor system. It does enhance performance however.

local function add(a: number, b: number) : number
   return a + b

add("hey", 5) -- warning

Oh ok, I thought it would change something when running code as well, thanks for telling me!


You mean

? >:D


I tried using generic functions and typed variadics, but this seems to generate a warning? It looks like it should work, since it returns all values and T... should be (number,number).

local function f<T...>(...:T...):T...
	return ...
local a,b = f(1,2)
-- W000: (5,1) Function only returns 0 values. 2 are required here

This also doesn’t seem to work.

local function f<T...>(...:T...):...any
	return ...
-- W000: (3,2) Failed to unify variadic packs

Shouldn’t everything be ok for ...any (any amount of values with any types)?

Am I doing something wrong in these examples, or are these bugs?


You are trying to use generic variadics that aren’t quite ready. The syntax you use means “T… refers to a tuple of types that don’t have to be the same”. Some bugs in this area will be fixed in the coming weeks with a proper announcement next month, as well as better error messages.

You can, however, do this today:

local function f<T>(...:T): ...T
	return ...

Which means that f() takes any number of values of the same type and returns all of them.