luau/docs/_posts/2020-10-30-luau-recap-octob...

9.9 KiB
Raw Blame History

layout title
single Luau Recap: October 2020

Luau is our new language that you can read more about at https://roblox.github.io/luau; weve been so busy working on the current projects that we didnt do an update in September, so lets look at changes that happened since August!

Many people work on these improvements, with the team slowly growing - thanks @Apakovtac, @EthicalRobot, @fun_enthusiast, @machinamentum, @mrow_pizza and @zeuxcg!

[Originally posted on the Roblox Developer Forum.]

Types are very close

Weve been in beta for a while now, but were steadily marching towards getting the first release of the type checker, what we call “types v0”, out of the door. It turns out that weve substantially underestimated the effort required to make the type system robust, strike the balance between “correct” and “usable” and give quality diagnostics in the event we do find issues with your code 🙂

Because of this, were changing the original plans for the release a bit. Were actively working on a host of changes that we consider to be part of the “v0” effort, and when they are all finished - which should happen next month, fingers crossed - were going to be out of beta!

However, by default, on scripts with no annotations, we wont actually activate type checking. You would have to opt into the type checking by using --!nonstrict or --!strict, at the top of each script. We are also going to open the second beta, “All scripts use non-strict mode by default” or something along these lines.

This is important because we found that our non-strict mode still needs some more work to be more tolerant to some code that occurs commonly in Roblox and is correct, but doesnt type-check. Were going to evaluate what changes specifically are required to make this happen, but we didnt want the extra risk of a flood of reports about issues reported in existing code to shift the release date in an unpredictable fashion.

To that end, weve been working on Lots and Lots and Lots and Lots and Lots of changes to finish the first stage. Some of these changes are already live and some are rolling out; the amount of changes is so large that I cant possibly list the up-to-date status on each one as these recaps are synthesized by the human who is writing this on a Friday night, so heres just a raw list of changes that may or may not have been enabled:

  • Strict mode is now picky about passing extra arguments to functions, even though they are discarded silently at runtime, as this can hide bugs
  • The error message about using a : vs . during type checking is now much more precise
  • Recursive type annotations shouldnt crash the type checker now, and we limit the recursion and iteration depth during type checking in a few cases in general in an effort to make sure type checker always returns in finite time
  • Binary relational operators (< et al) are now stricter about the argument types and infer the argument types better
  • Function argument and return types are now correctly contra- and co-variant; if this looks like gibberish to you, trust me - its for the best!
  • Fixed a few problems with indexing unions of tables with matching key types
  • Fixed issues with tracing types across modules (via require) in non-strict mode
  • Error messages for long table types are now trimmed to make the output look nicer
  • Improve the interaction between table types of unknown shape ({ [string]: X }) and table types of known shape.
  • Fix some issues with type checking table assignments
  • Fix some issues with variance of table fields
  • Improve the legibility of type errors during function calls - errors now point at specific arguments that are incorrect, and mismatch in argument count should clearly highlight the problem
  • Fix types for many builtins including ipairs, table.create, Color3.fromHSV, and a few others
  • Fix missing callbacks for some instance types like OnInvoke for bindables (I think this one is currently disabled while were fixing a semi-related bug, but should be enabled soon!)
  • Rework the rules under which globals are okay to use in non-strict mode to mostly permit valid scripts to type-check; strict mode will continue to frown upon the use of global variables
  • Fix a problem with the beta where two scripts with identical names would share the set of errors/warnings, resulting in confusing error highlights for code that doesnt exist
  • Improve the legibility of type errors when indexing a table without a given key
  • Improve the parsing error when trying to return a tuple; function f(): string, number is invalid since the type list should be parenthesized because of how our type grammar is currently structured
  • Type checker now clearly reports cases where it finds a cyclic dependency between two modules
  • Type errors should now be correctly sorted in the Script Analysis widget
  • Error messages on mismatches between numbers of values in return statements should now be cleaner, as well as the associated type mismatch errors
  • Improve error messages for comparison operators
  • Flag attempts to require a non-module script during type checking
  • Fix some cases where a type/typeof guard could be misled into inferring a non-sensible type
  • Increase the strictness of return type checks in strict mode - functions now must conform to the specified type signature, whereas before wed allow a function to return no values even in strict mode
  • Improve the duplicate definition errors to specify the line of the first definition
  • Increase the strictness of binary operators in strict mode to enforce the presence of the given operator as a built-in or as part of the metatable, to make sure that strict mode doesnt infer types when it cant guarantee correctness
  • Improve the type errors for cyclic types to make them more readable
  • Make type checker more friendly by rewording a lot of error messages
  • Fix a few crashes in the type checker (although a couple more remain - working on them!)
  • … I think thats it?
  • …edit ah, of course I forgot one thing - different enums that are part of the Roblox API now have distinct types and you can refer to the types by name e.g. Enum.Material; this should go live next week though. If you want to pretend that youve read and understood the entire list above, just know that weve worked on making sure strict mode is more reliably reporting type errors and doesnt infer types incorrectly, on making sure non-strict mode is more forgiving for code that is probably valid, and on making the type errors more specific, easier to understand, and correct.

Type syntax changes

Theres only two small changes here this time around - the type syntax is now completely stable at this point, and any existing type annotation will continue parsing indefinitely. We of course reserve the right to add new syntax thats backwards compatible :slight_smile:

On that note, one of the small changes is that weve finally removed support for fat arrows (=>); weve previously announced that this would happen and that thin arrows (->) are the future, and had warnings issued on the legacy syntax for a while. Now its gone.

On a positive note, weve added a shorter syntax for array-like table types. Whereas before you had to use a longer { [number]: string } syntax to declare an array-like table that holds strings, or had to define an Array type in every. single. module. you. ever. write. ever., now you can simply say {string}! This syntax is clean, in line with the value syntax for Lua table literals, and also was chosen by other research projects to add type annotations to Lua.

(if youre a monster that uses mixed tables, youll have to continue using the longer syntax e.g. { [number]: string, n: number })

Library changes

Theres only a few small tweaks here this time around on the functionality front:

  • utf8.charpattern is now exactly equal to the version from Lua 5.3; this is now possible because we support \0 in patterns, and was suggested by a user on devforum. We do listen!
  • string.pack now errors out early when the format specifier is Way Too Large. This was reported on dev forum and subsequently fixed. Note that trying to generate a Moderately Large String (like, 100 MB instead of 100 GB) will still succeed but may take longer than wed like - we have a plan to accelerate operations on large strings substantially in the coming months.

Performance improvements

We were super focused on other things so this is very short this time around. We have a lot of ideas here but they are waiting for us to finish some other large projects!

  • Method calls on strings via : are now ~10% faster than before. We still recommend using fully-qualified calls from string library such as string.foo(str), but extra performance never hurts!
  • Speaking of string methods, string.sub is now ~20% faster than before with the help of voodoo magic.

Miscellaneous fixes

There were a few small fixes that didnt land into any specific category that I wanted to highlight:

  • In some rare cases, debug information on conditions inside loops have been fixed to stop debugger from incorrectly suggesting that the current line is inside a branch that wasnt taken. As usual, if you ever see debugger misbehaving, please file bugs on this!
  • Code following assert(false) is now treated as an unreachable destination from the linting and type checking point of view, similarly to error calls.
  • Linting support for various format strings has been greatly improved based on fantastic feedback from @Halalaluyafail3 (thanks!).

Ok, phew, thats what I get for skipping a month again. Please dont hesitate to report bugs or suggestions, here or via separate posts. Due to our usual end-of-year code freeze theres going to be one more recap at the end of the year where we will look back at 2020 and take a small peek into the future.