Skip to content

const new bindings for loops and function parameters#192

Open
EgeDev003 wants to merge 3 commits intoluau-lang:masterfrom
EgeDev003:master
Open

const new bindings for loops and function parameters#192
EgeDev003 wants to merge 3 commits intoluau-lang:masterfrom
EgeDev003:master

Conversation

@EgeDev003
Copy link
Copy Markdown

@EgeDev003 EgeDev003 commented Apr 6, 2026

@EgeDev003 EgeDev003 changed the title Create const-binding-forin-loops-and-function-parameters.md const-binding-forin-loops-and-function-parameters.md Apr 6, 2026
@EgeDev003 EgeDev003 changed the title const-binding-forin-loops-and-function-parameters.md const new bindings for in and function parameters Apr 6, 2026
@TbeyazT
Copy link
Copy Markdown

TbeyazT commented Apr 7, 2026

Nice stuff man!

@EgeDev003
Copy link
Copy Markdown
Author

Actually, I was undecided about const in numeric for because I didn't know the runtime part, but as far as I looked, I saw that it had no effect on runtime, so I saw that it can be added to numeric loops, so I will edit this request in general.

@EgeDev003 EgeDev003 changed the title const new bindings for in and function parameters const new bindings for loops and function parameters Apr 7, 2026
@phasenull
Copy link
Copy Markdown

Makes sense but im not sure how i feel about declaring i in numeric loops as "constants", feels weird

@bradsharp
Copy link
Copy Markdown
Contributor

I am not sure if we should support const for numeric loops as, in other languages, this would prevent the loop variable from being incremented with each iteration.

@EgeDev003
Copy link
Copy Markdown
Author

You are actually right about what you said and numeric is actually a little different in purpose, if we look at the generic for, every variable there is actually different while in numeric i only it increases, but as far as I can see, there is compile time, not runtime, but it would be ridiculous to add it because of this I agree with that

The main purpose of the numeric is to prevent the change of the i in the scope, not to prevent the limit, step and index

for i = 1,10,1 do -- good and normal usage
  i *= 2
end

I mean

for const i = 1,10,1 do -- i normal increasing
  i *= 2 -- err
end

for example, if we take JavaScript as an example, we cannot do this, but this change does not contradict at the moment since Luau runs on a virtual machine independent of us and has no effect on the const runtime

At least as far as I know and see, it has no effect, but if there is it will be a direct contradiction and it would be absurd to add it, which my const idea in these new bindings was that I generally think about the places where we can assign variables, so I wanted to talk about it

@alexmccord
Copy link
Copy Markdown
Contributor

@bradsharp You'd be surprised.

for i = 1, 10 do
  print(i)
  i = 10
end

This will print 1, 2, 3, ... up to 10. The secret is that for loops are actually sugar for:

local <hidden> = 1
while <hidden> <= 10 do
  local i = <hidden>
  <hidden> += 1
  -- body
end

That's also why function() return i end in the body of the loop (both of them) always create a new closure per loop, each with a new upvalue i bound to the current index, whereas in JS or Python, it creates the same number of closures where every i is bound to 10.

The RFC is proposing to offer a way to make that line local i = <hidden> be const i = <hidden>. Same thing. This is not saying to make the binding that holds the index const. Then there's no violation happening here.

@Crazyblox
Copy link
Copy Markdown

I think this would be a great extension of the const keyword's utility and, as with the initial const implementation, help reduce cognitive load.

What @alexmccord said also makes me feel comfortable in supporting this as it looks pretty straight forward when you consider that values declared in places like function/for blocks are already made local to the given scope.

Much like the type checker, I like the linter being able to tell me if something I'm doing is either not intended by definition or would cause issues; this would be a time saver for me, and I can imagine something like this would further assist in my ability to skim and make quick edits to unfamiliar code with lower risk of breaking stuff, saving time.

Extending const like this could also improve the range of how far someone can get away with their code being self-documented; reducing any potential burden on the user to provide documentation.

@Ukendio
Copy link
Copy Markdown

Ukendio commented Apr 10, 2026

I will take the brunt of being the dissenting voice here I suppose.

To preface: I think the const keyword is a misguided attempt at solving a problem that isn’t particularly meaningful in Luau. It primarily acts as a way to police style rather than enforce important semantics. It doesn’t meaningfully change aliasing, mutation, or data flow. It only enforces whether a variable can be reassigned. And it does not unlock anything such as cross module inlining as it was initially sold as that we now know is untrue.

I think you may have inadvertently or consciously used javascript as a reference for the loop (as I think I saw in the ROSS server ) but I think it is the incorrect language to follow in the footsteps here. Javascript creates a new scope for each iteration because variables are hoisted. That means the variables exist in the temporal dead zone before they enter the scope where they get declared. If you reference that same variable before it was initialized then you will get a ReferenceError. As I alluded to earlier, we do not have this issue! If you do the same thing in luau, you will just get nil state because the lexical scope in a loop is not actually real like it is in JS.

Unlike js, luau has great rules for lexical scoping which eliminate a large class of issues that other languages try to fix with const . Overall I would be disappointed to see the language expand on a feature in a direction that adds surface level restrictions.

@MagmaBurnsV
Copy link
Copy Markdown
Contributor

I also think this is a bad idea since it encourages littering const everywhere even when there's no tangible benefit. No one is accidently reassigning for-loop and parameter bindings, but it becomes "good practice" to write const function f(const x: number, ...) boilerplate because in theory it's safer.

This was what I liked a lot about Luau pre-const. There was only local for writing variables and "don't reassign" was conveyed by style preference. Now the choice of keyword is also opinionated, which will inevitably lead to more style divergence in the ecosystem. Let's not fragmentate any further.

@Skekdog
Copy link
Copy Markdown

Skekdog commented Apr 11, 2026

I also agree with this dissent. I actually recently did accidentally reassign a function parameter, resulting in a bug; however, needing const in front of everything seems very verbose, and as said above, would likely become best practice - at the cost of this verbosity. To my understanding, this also wouldn't unlock any new optimisation possibilities.

For me personally, I think a lint (built-in to Luau or otherwise) against reassigning function parameters would be better.

In terms of for loops:
for const k, v in table reads to me like both k and v are const. Needing const in front of both is again very verbose.

@Cooldude2606
Copy link
Copy Markdown

In terms of for loops:
for const k, v in table reads to me like both k and v are const. Needing const in front of both is again very verbose.

I am in favour of const and generally agree with the RFC. However, I also agree with this comment here. Needing const on both is quite verbose and conflicts with current assignment syntax.

Namely, const foo, bar = "fizz", "buzz"
We dont write, const foo, const bar = "fizz", "buzz"

I also do not see much use in being able to mix and match const bindings in for loop variables. All or nothing seams like it would cover the vast majority of useful situations for const in loops. So instead having a single const make all loop bindings const should be sufficient, while also reading cleaner.

@EgeDev003
Copy link
Copy Markdown
Author

I understand you, but in this case:

for const key, value in tbl do
    value = ... --you can't change
end

do you have any suggestions on what we can do in this case?

@Cooldude2606
Copy link
Copy Markdown

do you have any suggestions on what we can do in this case?

Id argue this case is an anti-pattern. Either you will be wanting to reassign key and value, or neither. And for arguments sake, say value is an array which you filter and reassign. Then it would be better practice to assign to a new binding rather than the existing one.

for const key, array in tbl do
    const filtered = filter(array, pred)
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants