Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: If statement initializers #23

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions docs/syntax-if-statements-initializers.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ Introduce an initializer expression that declares and initializes variables in i

# Motivation

Initializers can improve code clarity and reduce scope pollution by allowing developers to declare variables in the conditions of if statements. ⁤⁤ Declaring variables at the point of use in if statements for the scope of the if statement's block simplifies code, leading to better readability and understanding of program logic. By limiting the scope of variables to the condition's pertaining block, the risk of unintended variable reuse and naming conflicts is reduced. ⁤
Initializers can improve code clarity and reduce scope pollution by allowing developers to declare variables in the conditions of if statements. ⁤⁤ Declaring variables at the point of use in if statements for the scope of the if statement's blocks simplifies code, leading to better readability and understanding of program logic. By limiting the scope of variables to the if statement's blocks, the risk of unintended variable reuse and naming conflicts is reduced. ⁤

The reduced scope pollution improves register space in extreme cases (or auto-generated code) where developers have many variables defined and have to work around register limits by reducing the register size. In some scenarios, especially on Roblox, initializing variables within if statements can lead to improved performance and reduced complexity by avoiding unnecessary calls by developers. ⁤ A common paradigm used by Roblox developers is to use `Instance:FindFirstChild` in their condition and then access it afterwards instead of keeping an existing variable around in the new scope, polluting the existing scope.

# Design

If statements with initializers must match (following the Luau grammar) `'if' 'local' bindinglist ['=' explist] 'then'` and `'local' bindinglist ['=' explist] where exp 'then'` syntax. The variables declared by the initializer are only available to the block of that condition and will be undefined to the `elseif` conditions and blocks as well as the `else` block; any code after the if statement won't have the variables defined either.
If statements with initializers must match (following the Luau grammar) `'if' 'local' bindinglist ['=' explist] 'then'` and `'local' bindinglist ['=' explist] where exp 'then'` syntax. The variables declared by an initializer are only available to the if statement's blocks; any code after the if statement won't have the variables defined.
alexmccord marked this conversation as resolved.
Show resolved Hide resolved

In the former case, the value of the first declared variable will be checked.

Expand All @@ -24,13 +24,13 @@ local function foo()
end

if local b = foo() then
print(b)
print(b, "truthy block")
else
print("false")
print(b, "falsy block")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to add that this design point is one we have to live with in perpetuity. If we decided to take this fallthrough semantics out of this RFC, then we're stuck with that behavior.

Using boolean is an ok example, but it doesn't strongly argue for it as opposed to some other example I posted earlier wrt animal and one that @vegorov-rbx posted with pcall example. If a design point is a "choose now or forever hold your peace," it especially needs an equally as compelling argument to support it.

So I'd rather block the RFC until we are able to agree on this design point, whether locals should fallthrough or not.

An example where the behavior is breaking change would also be good to include in the alternatives section.

if local x = f() in x % 2 == 0 then
  print(x) --> any even numbers
else
  print(x) --> nil
end

As is, this RFC proposes the print(x) in the else branch to print any odd numbers.

end
```

`Output: true`
`Output: true truthy block`

In the latter case, the `exp` condition is checked rather than the initializer.

Expand All @@ -42,15 +42,15 @@ local function foo()
end

if local b = foo() where b == false then
print(b)
print(b, "truthy block")
else
print("true")
print(b, "falsy block")
end
```

`Output: true`
`Output: true falsy block`

When declaring multiple values inside of a condition, all of the variables will be tested for truthiness.
When declaring multiple values inside of an initializer, the `where` clause is required.

Example:

Expand All @@ -59,7 +59,7 @@ local function foo()
return true, false
end

if local a,b = foo() then
if local a,b = foo() where a and b then
else
print'Hello World, from Luau!'
end
Expand Down