Will Luau support assignment expressions?

After doing today’s LeetCode daily, I was wondering if Luau might potentially implement something like Python’s walrus operator. Here’s what little I could find about it:

Will developers find it useful to be able to initialize variables and evaluate them in the same line, in a readable manner? How come this doesn’t have much attention? Is this not an improvement to writing game development code?

will never happen for a simple reason, being a lightweight, simple and easy to use language

How does this go against being lightweight, simple, and easy to use?

It will complicate the bytecode and parser for zero real gain
Currently control-flow expressions in Luau are simple:
if expects a boolean expression
while expects a boolean expression

Introducing local definitions there forces the language to support a new special grammar only for these spots.
This means:
1. New parser rules
2. New bytecode patterns
3. New scope semantics

It would also break current scoping model

if local a = expr() then
    print(a) --// should this be allowed? yes?
end
print(a) --// should this be allowed? no?

Luau would need a unique hidden scope, that only exists before the if-block but not after.

It will also create confusing code, that will encourage hiding logic.
This is readable:

local v = getValue()
if v then
    print("exists")
end

This is not:

if local v = getValue() then 
    print("exists")
end

Basically you gain no performance gain from local definitions in control flow.
Luau is micro-optimized bytecode language, with each opcode being used as much as possible, adding more VM work just for “confusing” readability is not going to be a good thing at all.

I’m envisioning something like:

Current

local Players = game:GetService("Players")

local function check_if_player_hits(hit)
    local hit_parent = hit.Parent
    local Humanoid = hit_parent:FindFirstChildOfClass("Humanoid")

    if Humanoid and Players:GetPlayerFromCharacter(hit_parent) then
        local Player = Players:GetPlayerFromCharacter(hit_parent)

        print("Touched")
    end
end

Proposed

local Players = game:GetService("Players")

local function check_if_player_hits(hit)
    local hit_parent = hit.Parent
    local Humanoid = hit_parent:FindFirstChildOfClass("Humanoid")

    if Humanoid and (local Player := Players:GetPlayerFromCharacter(hit_parent)) then
        print("Touched")
    end
end

Where I purposely want Player and Humanoid to be in different scopes

Could I write this better without repeating Players:GetPlayerFromCharacter(...) while preserving this scope requirement?

it’s important how your code works and how you think

assuming your function only detects hits for a Player, you could first check if it’s a player, then getting the humanoid, which will save you unnoticeable performance.

local function check_if_hits(hit)
    local hit_parent = hit.Parent
    if Players:GetPlayerFromCharacter(hit_parent) then
        local Humanoid = hit_parent:FindFirstChildOfClass("Humanoid")
        print("Touched")
    end
end

now Humanoid is referenced only if it’s an actual Player.
if you want to save any tiny bit of ms of performance, you need to do every micro-optimization

Okay, so how does this preserve the scope requirement?

why do you need to change how scopes work?

Sorry if I am misunderstanding, but I wanted to keep a Player variable somewhere

Why would you need player in the more specific scope though? Keeping stuff in the most specific scope is generally ideal, but I have a hard time understanding why you wouldn’t just do this

local Player = Players:GetPlayerFromCharacter(hit_parent)
if Humanoid and Player then
    print("Touched")
end

It’s not really in too high a scope for what it is

you can use do end scope block

I can’t conjure up a better example at the moment, but I do get that it’s not natural to want to keep a Player at a more specific scope than Humanoid

I just think that the repetition of checking and then initializing after the check is a redundancy that could be removed in other code examples (that I can’t think of atm)

But, if I’m wrong, then this is disproven I guess

Doesn’t this make it less readable in my example lol

it’s a whole block with a body, unlike a statement as a condition in if and while control flows, so no, it doesn’t make it less readable

No, like, can you give me a clearer rewrite of my example using do end? I know what a do end block is

I know I’ve definitely done this before but I cannot think of a time I’ve done this that I wasn’t able to rewrite it in some way as it is above. Maybe I’m just forgetting a random edge case though.

I would say no.

local Player = Players:GetPlayerFromCharacter(hit_parent)
if Humanoid and Player then
    print("Touched")
end

vs

do
    if Humanoid and Players:GetPlayerFromCharacter(hit_parent) then
        print("Touched")
    end
end

Though at this point we should probably just be doing

if Humanoid then
    local Player = Players:GetPlayerFromCharacter(hit_parent)
    if Player then
        print("Touched")
    end
end
1 Like
local function check_if_player_hits(hit)
    local hit_parent = hit.Parent

    do
        local Humanoid = hit_parent:FindFirstChildOfClass("Humanoid")
        if not Humanoid then
            return
        end

        do
            local Player = Players:GetPlayerFromCharacter(hit_parent)
            if not Player then
                return
            end
        
            print("Touched")
        end
    end
end

But again, you don’t need to code like this, you can code a perfectly good code without using do .. end blocks.

I’d do this:

local function check_if_player_hits(hit)
    local hit_parent = hit.Parent

    local Player = Players:GetPlayerFromCharacter(hit_parent)
    if not Player then return end

    local Humanoid = hit_parent:FindFirstChildOfClass("Humanoid")
    if not Humanoid then return end

    print("Touched")
end

Now Humanoid will only be referenced if it’s an actual Players body part

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.