Acquis 3 - If-Assignment

The if and elseif statements can now include assignments in their conditions. Variables assigned in conditions are scoped to the entire conditional block, including all elseif and else branches.

Syntax

Assignments use the = operator within the condition:

if var = expr then
    -- var is available here
end

if a, b, c = expr1, expr2, expr3 then
    -- all variables available here
end

The condition is true when all assigned values are truthy (not nil or false). If any value is falsy, the condition fails and the next branch executes.

if x = 42 then
    print(x)  -- prints 42
end

if x = nil then
    print("never reached")
else
    print("x was nil")
end

Single variable assignment

The simplest form assigns one value and tests it:

local function getData()
    return { value = 100 }
end

if data = getData() then
    print(data.value)  -- 100
end

This is particularly useful for functions that return nil on failure:

local function findUser(id)
    return users[id]  -- may be nil
end

if user = findUser(123) then
    print(user.name)
else
    print("User not found")
end

Multiple variable assignment

Multiple variables can be assigned and tested simultaneously:

if a, b, c = 1, 2, 3 then
    print(a + b + c)  -- 6
end

The condition fails if any assigned value is falsy:

if a, b, c = 1, nil, 3 then
    print("never reached")  -- b is nil
elseif d = 4 then
    print(a, b, c, d)  -- 1, nil, 3, 4
end

Variable scoping

Variables declared in conditions persist through all branches:

if a = nil then
    -- a is nil, condition false
elseif b = nil then
    -- a and b available, both nil, condition false
else
    -- a and b both available here
    print(a, b)  -- nil, nil
end

This enables progressive narrowing:

if primary = getPrimary() then
    use(primary)
elseif secondary = getSecondary() then
    use(secondary)
else
    -- primary and secondary both nil
    useDefault()
end

With multiple return values

Functions returning multiple values work naturally:

local function getCoordinates()
    return 10, 20
end

if x, y = getCoordinates() then
    print(x, y)  -- 10, 20
end

If fewer values are returned than variables, extras become nil and the condition fails:

local function getOne()
    return 100
end

if a, b = getOne() then
    print("never reached")  -- b is nil
end

With catch expressions

If-assignment composes naturally with catch:

if ok, result = catch riskyOperation() then
    print("Success:", result)
else
    print("Error:", result)  -- result is the error message
end

Motivation

Lua does not allow assignments in conditional expressions. Testing a value often requires separate declaration and condition statements.

Redundant code

A common Lua pattern:

-- Lua: separate assignment and test
local result = compute()
if result then
    use(result)
end

With if-assignment:

-- Lus: combined
if result = compute() then
    use(result)
end

Scoping issues

In Lua, variables declared for conditions pollute the outer scope:

-- Lua: result visible after if block
local result = compute()
if result then
    process(result)
end
-- result still in scope here

With if-assignment, variables are scoped to the conditional block:

-- Lus: result scoped to conditional
if result = compute() then
    process(result)
end
-- result not visible here

Multiple fallback patterns

Chained fallbacks are verbose in Lua:

-- Lua: verbose fallback chain
local primary = getPrimary()
if primary then
    use(primary)
else
    local secondary = getSecondary()
    if secondary then
        use(secondary)
    else
        useDefault()
    end
end

With if-assignment:

-- Lus: flat fallback chain
if primary = getPrimary() then
    use(primary)
elseif secondary = getSecondary() then
    use(secondary)
else
    useDefault()
end