news-2021-09-30-luau-recap-september-2021.md
September 30, 2021
The big news this month is that generic functions are back!
Luau has always supported type inference for generic functions, for example:
but up until now, there’s been no way to write the type of swap, since Luau didn’t have type parameters to functions (just regular old data parameters). Well, now you can:
Generic functions can be used in function declarations, and function types too, for example
People may remember that back in April we announced generic functions, but then had to disable them. That was because DataBrain discovered a nasty interaction between typeof and generics, which meant that it was possible to write code that needed nested generic functions, which weren’t supported back then.
Well, now we do support nested generic functions, so you can write code like
and have Luau infer a type where a generic function returns a generic function
For people who like jargon, Luau now supports Rank N Types, where previously it only supported Rank 1 Types.
Up until now, Luau has used bottom-up typechecking. For example, for a function call f(x) we first find the type of f (say it’s (T)->U) and the type for x (say it’s V), make sure that V is a subtype of T, so the type of f(x) is U.
This works in many cases, but has problems with examples like registering callback event handlers. In code like
if we try to typecheck this bottom-up, we have a problem because we don’t know the type of other when we typecheck the body of the function.
What we want in this case is a mix of bottom-up and top-down typechecking. In this case, from the type of part.Touched:Connect we know that other must have type BasePart.
This mix of top-down and bottom-up typechecking is called bidirectional typechecking, and means that tools like type-directed autocomplete can provide better suggestions.
We have made some improvements to the Luau-powered autocomplete beta feature in Roblox Studio:
Player.PlayerGui.then and else are autocompleted better.--[[).In other typechecking news:
typeof(foo) ~= "Instance" eliminates anything not a subclass of Instance.return statements interact with mutually recursive function declarations.*unknown* rather than as an internal type name like error####.Instance:Clone() much more accurately.Vector3.new constructor has been optimized and is now ~2x fastersetmetatable is used, such as local self = setmetatable({}, Klass)debug.traceback is now 1.5x faster, although debug.info is likely still superior for performance-conscious code{ [1] = 42 }, is now noticeably faster, although list-style construction is still recommended.{ [1] = 1, [1] = 2 }