Appearance
Implemented RFCs
Written: 2026-10-14
Learning objectives
- You read the status line on any Luau RFC page.
- You tell a merged proposal apart from a shipped feature.
- You name which Level 6 features you can use today.
- You name which proposals you must not use yet.
- You test every new feature in Studio before you ship it.
Prerequisites
How status works
An RFC page carries its verdict at the top. You look for one line.
When the page shows Status: Implemented, the feature is available in Luau. You can use it. Every chapter in this level links the RFC page that carries this line.
When the page shows no such line, the feature is not available. A merged proposal is not a shipped feature. The RFC process says a merged RFC only means the change can be implemented. Implementation lands later, sometimes months later. The same process says the RFC gains the Implemented line only when the work ships behind a feature flag.
Amendment RFCs refine older RFCs instead of editing them. You read both pages. The require aliases page keeps a paths section that a later amended require page marks obsolete. The user-defined type functions page documents a class tag that a later extern tag page renames to extern. The newer page wins.
You build Roblox experiences, so you add one more check. Studio ships Luau on its own schedule. A feature can carry the Implemented line and still be missing from your Studio build. You test each feature in Studio before you depend on it.
Run this pure snippet in the Command Bar to confirm your Studio understands a recent feature.
luau
--!strict
const reward = 50
print(reward)You bind 50 with const. You print it. When this runs, your Studio supports const bindings. When it errors, your Studio lags behind the language. The const RFC carries the Implemented line either way.
Implemented RFCs you learn in this level
You can use every feature below. Each one links the RFC page that carries the Implemented line. Each chapter teaches the semantics and the strict-mode consequences.
| Area | Feature | RFC status page |
|---|---|---|
| Syntax | String interpolation | syntax-string-interpolation |
| Syntax | Compound assignment | syntax-compound-assignment |
| Syntax | If expressions | syntax-if-expression |
| Syntax | Generalized iteration | generalized-iteration |
| Syntax | Const bindings | const-keyword |
| Generics | Named function type arguments | syntax-named-function-type-args |
| Generics | Typed variadics | syntax-typed-variadics |
| Generics | Type alias type packs | syntax-type-alias-type-packs |
| Generics | Default type alias parameters | syntax-default-type-alias-type-parameters |
| Generics | Explicit instantiation | explicit-type-parameter-instantiation |
| Types | Sealed table subtyping | sealed-table-subtyping |
| Types | Unsealed table literals | unsealed-table-literals |
| Types | Unsealed assignment of optionals | unsealed-table-assign-optional-property |
| Types | Stripping optionals in subtyping | unsealed-table-subtyping-strips-optional-properties |
| Types | Never and unknown | never-and-unknown-types |
| Types | Bidirectional casts | syntax-type-ascription-bidi |
| Types | Function attributes | syntax-attributes-functions |
| Type functions | User-defined type functions | user-defined-type-functions |
| Type functions | Generics in type functions | support-for-generic-function-types-in-user-defined-type-functions |
| Type functions | Thread and buffer in type functions | support-for-thread-and-buffer-types-in-user-defined-type-functions |
| Type functions | Index operator | index-type-operator |
| Type functions | Keyof operators | keyof-type-operator |
| Type functions | Rawget operator | rawget-type-operator |
| Type functions | Metatable operators | metatable-type-functions |
| Type functions | Type issubtypeof | method-type-issubtypeof |
| Type functions | Types optional | types-library-optional |
| Type functions | Extern tag | udtf-is-extern |
| Library | Math lerp | function-math-lerp |
| Library | Math map | function-math-map |
| Library | Isnan, isinf, isfinite | math-isnan-isfinite-isinf |
| Library | Vector lerp | function-vector-lerp |
| Library | Buffer bits | function-buffer-bits |
| Config | Require aliases | require-by-string-aliases |
| Config | Amended require | amended-require-resolution |
| Config | Init dot luau | abstract-module-paths-and-init-dot-luau |
| Config | Config dot luau | config-luauconfig |
| Config | Error suppression | type-error-suppression |
You study them in this order. Start with syntax. Then read generics and packs. Then read type system RFCs. Then read type functions. Finish with stdlib and config.
Accepted but not implemented
The proposals below have RFC pages but no Implemented line. You must not use them in your games. Each sketch below is labeled and you do not run it.
| Proposal | RFC page | What you do instead |
|---|---|---|
| 64-bit integers | type-long-integer | You stay on number for scores and currency. You split huge ids into two numbers or strings. |
| Classes | syntax-classes | You build class-like tables with metatables and constructors as taught in metatables and OOP. |
| Cyclic requires | support-for-cyclic-requires | You keep your require graph acyclic. You move shared types into a leaf module both sides require. |
| Export by value | export-keyword | You return a frozen table from your module. You keep one return at the end. |
| Negation types | negation-types | You write unions and intersections you can already express. You narrow with typeof and truthiness. |
| Cast by inhabitance | type-ascription-by-inhabitance | You use the bidirectional cast rule taught in type system RFCs. You route unclear casts through unknown with a guard. |
The class syntax from the proposal is NOT YET AVAILABLE, do not run. The block below is the runnable replacement, not the proposal syntax.
luau
--!strict
local point = { x = 3, y = 4 }
print(point.x)You want a Point class with methods. You write a table with x and y instead. You add a constructor function in your module. The classes page has no Implemented line, so the class block stays out of your code.
The integer suffix from the proposal is NOT YET AVAILABLE, do not run. The block below is the runnable replacement, not the proposal syntax.
luau
--!strict
local score = 9007199254740993
print(score)You want exact integers past the float boundary. You store the id as a string instead. You compare strings for equality. The integer page has no Implemented line, so the integer suffix stays out of your code.
Why the distinction matters in Roblox
Your game runs on Studio and on player devices. Both can lag behind the language. A feature you read about today can be missing from the build your players use.
You test every new feature before you depend on it. You open a blank place. You run a tiny snippet that uses only that feature. You watch the output. You check strict mode too, because the solver version can lag separately from the runtime.
You isolate new syntax per file. When one file uses a feature your build lacks, only that file breaks. Your core systems keep loading. You keep a fallback shape ready, usually the older syntax the RFC replaced.
You read amendment RFCs before you configure a project. The amended require page removes the paths array the older aliases page describes. A tutorial that teaches paths will mislead you. The RFC page itself tells you the section is obsolete.
Common mistakes
Wrong: you treat a merged RFC as shipped.
luau
--!strict
local earned = 10
earned += 5
print(earned)This one is fine because the compound assignment page carries the Implemented line. The mistake is the habit, not this snippet. Fix the habit by opening the RFC page and reading the status line first.
Wrong: you copy class syntax from the classes proposal into a Studio script.
luau
--!strict
local enemy = { health = 100 }
print(enemy.health)You wanted a class block. You write a plain table instead. You add behavior with functions in the module. Fix it by checking the classes page for the missing Implemented line.
Wrong: you assume Studio matches the language site on day one.
luau
--!strict
local label = if 2 > 1 then "yes" else "no"
print(label)The if expression page carries the Implemented line, yet an old Studio build can still reject it. Fix it by running the snippet in your Studio before you build on it.
Exercises
- Open three RFC pages and record each status line as Implemented or missing.
- Pick one Implemented feature and run a five-line proof snippet in Studio.
- Rewrite a class-shaped design as a metatable module with a constructor.
Solution 1
Open the string interpolation, classes, and math lerp pages. Record Implemented for interpolation and lerp. Record missing for classes. You now trust the status line.
Solution 2
Run this pure snippet in the Command Bar.
luau
--!strict
local level = 7
local title = if level >= 5 then "veteran" else "rookie"
print(title)txt
veteranYou prove if expressions work in your build. The condition picks veteran. You print it. When this fails, you stop and update Studio.
Solution 3
Run this pure snippet in the Command Bar.
luau
--!strict
local Chest = {}
Chest.__index = Chest
function Chest.new(gold: number)
local self = { gold = gold }
setmetatable(self, Chest)
return self
end
local first = Chest.new(25)
print(first.gold)txt
25You replace the unavailable class block with a table plus metatable. You construct with new. You print the field. That pattern carries you until classes ever ship.
Summary
- Only the Implemented line means available. Merged means possible.
- Amendment RFCs override older pages. You read both.
- Six proposals in this level stay unavailable. You use the workarounds above.
- Studio can lag the language. You prove each feature in Studio.
- Next: Syntax RFCs.