This meta-RFC proposes removing the previously accepted RFC on safe navigation operator. This is probably going to be disappointing but I feel like this is the best course of action that reflects our ideals in language evolution. ## Problem The RFC specifies a new navigation operator, `?.`, that returns `nil` when the left hand side is `nil`, as well as skipping the rest of the indexed chain evaluation (e.g. `vehicle.Turret?.Frame.CFrame.LookVector` evaluates to `nil` if `vehicle.Turret` is `nil`). Initially the RFC only specifies this one operator, although future extensions like `?:`, `?[]`, `?()` are possible -- the RFC stands on its own, but it opens the path to more "nil-safe" operators in the future. Unfortunately, we discovered a significant problem (after the RFC was merged) in the operator, in its interaction with the Roblox instance hierarchy. This is a userdata based DOM tree that (unfortunately) overloads __index to access children, and (fortunately?) attempting to access a non-existent child raises an error. As such, it's not compatible with this proposal in the sense that trying to use `?.` in combination with the instance hierarchy will only work if the child is present, and will raise an error otherwise. ## Alternatives There are several ways to address that problem and still ship this; all of them are unsatisfactory: 1. We can change the instance hierarchy at Roblox to return `nil` instead. If Luau existed 15 years ago with `?.` feature, we probably would not have implemented dot-access in the first place, or maybe had it return `nil`... However, at present this is a very significant change that very dramatically changes the contract around instance access and may have large unintended consequences. It's something that isn't obviously a good idea in the first place, and not something we'd want to do for a single language feature as other features may pull us into maintaining the status quo instead. 2. We can ignore this footgun and/or try to help with static analysis. The issue here is that static analysis must depend on us knowing the precise type and tree location of the first object in the chain, something that will very often not work reliably, and the pattern is too convenient and too common - so we should probably admit that with or without analysis, people will be hitting this often accidentally. This can be treated as a reasonable compromise - we're adding a convenient feature that requires a little care around some constructs, and as long as the users "know what they are doing" it's going to be okay - but my perspective is that we should try to keep the language as free of footguns / as orthogonal / as simple as possible, and any feature that has significant issues around these must be a critical feature we can't live without for us to tolerate these. 3. We can introduce a new metamethod, `__safeindex`, that will be called for `?.` instead of `__index`, if present. This metamethod can then be defined for Roblox instance hierarchy to return `nil`. My perspective here is that while it removes the footgun, it violates the orthogonality / simplicity of the null safety operators in general - just for this one operator it now requires new VM opcodes, new table lookup functions that use either `__safeindex` or `__index` metamethods, and creates questions for any future null safety operators wrt whether or not we will go through the same process for consistency (eventually yielding `__safecall`, `__safenewindex`, `__safeadd` etc. in the extreme), or if `__safeindex` is a one-off ad hoc addition to solve a specific problem we have for one of the (well, largest) users of Luau language. This turns the safe navigation operator from "cheap convenient syntax sugar" to "full blown operator every element of the stack must be aware of", which - again, in my perspective - shifts the balance for this feature, as the costs no longer seem to justify the benefit. ## Conclusion While we have ways forward for this proposal, they either make the language less robust [when used in Roblox environment], mean this feature is much less orthogonal/simple than initially understood, or mean we need to dramatically change the access rules [in Roblox environment] for a single small language feature. While it's unusual to judge a feature of a general purpose language based on a single user of the said language, given Luau's heritage and the fact that the majority of the programmers who interact with Luau presently use it in context of Roblox, I think we must take this into account. These situations will probably happen rarely - in fact it's the first feature proposal like this! - but when they do, we should strive to keep the language simple and devoid of footguns, thus I believe it's overall beneficial to maintain the status quo and not implement this proposal. As suggested in the RFC, this still means you can use `and` operator as a replacement for very basic single-element chains, e.g. `dog and dog.name`, but for more complex chains with `nil`s unfortunately the existing longer patterns must be used. We plan to look into common subexpression elimination that, under certain conditions, will allow us to maximally efficiently evaluate seemingly redundant expressions like `foo and foo.bar and foo.bar.baz`, and if that doesn't work you'd need to settle for multiple expressions to evaluate these chains efficiently in presence of nils - that said, I think in this case shorter code for some cases like this is not a strong enough motivation to ship the feature in the face of the problem discussed above. cc @Kampfkarren for visibility |
||
---|---|---|
.github | ||
Analysis | ||
Ast | ||
bench | ||
CLI | ||
Compiler | ||
docs | ||
extern | ||
fuzz | ||
papers | ||
prototyping | ||
rfcs | ||
tests | ||
tools | ||
VM | ||
.clang-format | ||
.gitignore | ||
CMakeLists.txt | ||
CONTRIBUTING.md | ||
LICENSE.txt | ||
lua_LICENSE.txt | ||
Makefile | ||
README.md | ||
SECURITY.md | ||
Sources.cmake |
Luau

Luau (lowercase u, /ˈlu.aʊ/) is a fast, small, safe, gradually typed embeddable scripting language derived from Lua.
It is designed to be backwards compatible with Lua 5.1, as well as incorporating some features from future Lua releases, but also expands the feature set (most notably with type annotations). Luau is largely implemented from scratch, with the language runtime being a very heavily modified version of Lua 5.1 runtime, with completely rewritten interpreter and other performance innovations. The runtime mostly preserves Lua 5.1 API, so existing bindings should be more or less compatible with a few caveats.
Luau is used by Roblox game developers to write game code, as well as by Roblox engineers to implement large parts of the user-facing application code as well as portions of the editor (Roblox Studio) as plugins. Roblox chose to open-source Luau to foster collaboration within the Roblox community as well as to allow other companies and communities to benefit from the ongoing language and runtime innovation.
This repository hosts source code for the language implementation and associated tooling, documentation for the language as well as RFCs and other materials. The documentation portion of this repository can be viewed at https://luau-lang.org/
Usage
Luau is an embeddable language, but it also comes with two command-line tools by default, luau
and luau-analyze
.
luau
is a command-line REPL and can also run input files. Note that REPL runs in a sandboxed environment and as such doesn't have access to the underlying file system except for ability to require
modules.
luau-analyze
is a command-line type checker and linter; given a set of input files, it produces errors/warnings according to the file configuration, which can be customized by using --!
comments in the files or .luaurc
files. For details please refer to type checking and linting documentation.
You can download the binaries from a recent release.
Building
To build Luau tools or tests yourself, you can use CMake on all platforms:
mkdir cmake && cd cmake
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build . --target Luau.Repl.CLI --config RelWithDebInfo
cmake --build . --target Luau.Analyze.CLI --config RelWithDebInfo
Alternatively, on Linux/macOS you can use make:
make config=release luau luau-analyze
To integrate Luau into your CMake application projects, at the minimum you'll need to depend on Luau.Compiler
and Luau.VM
projects. From there you need to create a new Luau state (using Lua 5.x API such as lua_newstate
), compile source to bytecode and load it into the VM like this:
// needs lua.h and luacode.h
size_t bytecodeSize = 0;
char* bytecode = luau_compile(source, strlen(source), NULL, &bytecodeSize);
int result = luau_load(L, chunkname, bytecode, bytecodeSize, 0);
free(bytecode);
if (result == 0)
return 1; /* return chunk main function */
For more details about the use of host API you currently need to consult Lua 5.x API. Luau closely tracks that API but has a few deviations, such as the need to compile source separately (which is important to be able to deploy VM without a compiler), or lack of __gc
support (use lua_newuserdatadtor
instead).
To gain advantage of many performance improvements it's highly recommended to use safeenv
feature, which sandboxes individual scripts' global tables from each other as well as protects builtin libraries from monkey-patching. For this to work you need to call luaL_sandbox
for the global state and luaL_sandboxthread
for each new script's execution thread.
Testing
Luau has an internal test suite; in CMake builds it is split into two targets, Luau.UnitTest
(for bytecode compiler and type checker/linter tests) and Luau.Conformance
(for VM tests). The unit tests are written in C++, whereas the conformance tests are largely written in Luau (see tests/conformance
).
Makefile builds combine both into a single target and can be ran via make test
.
Dependencies
Luau uses C++ as its implementation language. The runtime requires C++11, whereas the compiler and analysis components require C++17. It should build without issues using Microsoft Visual Studio 2017 or later, or gcc-7 or clang-7 or later.
Other than the STL/CRT, Luau library components don't have external dependencies. The test suite depends on doctest testing framework, and the REPL command-line depends on isocline.
License
Luau implementation is distributed under the terms of MIT License. It is based on Lua 5.x implementation that is MIT licensed as well.
When Luau is integrated into external projects, we ask to honor the license agreement and include Luau attribution into the user-facing product documentation. The attribution using Luau logo is also encouraged.