lus

Acquis 4 - Table Destructuring

Contents (12)
  1. Syntax
  2. Local destructuring
  3. Global destructuring
  4. Bare assignment
  5. Missing fields
  6. Nested tables
  7. Function return values
  8. Conditional expressions
  9. Motivation
    1. Repetitive field access
    2. Function parameter patterns
    3. Module imports

The from keyword enables table destructuring, extracting fields into variables based on their names. This provides a concise alternative to manually accessing each field.

Syntax#

The from keyword follows a variable list and precedes a table expression:

local a, b, c from table_expr

This is equivalent to:

local a, b, c = table_expr.a, table_expr.b, table_expr.c

The variable names determine which fields are extracted. The table expression is evaluated once.

Local destructuring#

Declare local variables and extract matching fields:

local t = { x = 10, y = 20, z = 30 }
local x, y, z from t
assert(x == 10 and y == 20 and z == 30)

Variables can be listed in any order:

local t = { a = 1, b = 2, c = 3 }
local c, a from t  -- order doesn't match table
assert(a == 1 and c == 3)

Global destructuring#

Use global for global variable declarations:

local t = { config = "default", timeout = 30 }
global config, timeout from t
assert(_G.config == "default")
assert(_G.timeout == 30)

Bare assignment#

Existing variables can be assigned using bare destructuring:

local x, y
local t = { x = 100, y = 200 }
x, y from t
assert(x == 100 and y == 200)

This is useful for reassignment:

local x, y = 0, 0
local t1 = { x = 1, y = 1 }
local t2 = { x = 2, y = 2 }

x, y from t1
assert(x == 1 and y == 1)

x, y from t2
assert(x == 2 and y == 2)

Missing fields#

Fields that don’t exist in the table become nil:

local t = { a = 1 }
local a, b, c from t
assert(a == 1)
assert(b == nil and c == nil)

Nested tables#

Destructuring works with nested table access:

local outer = { inner = { value = 42 } }
local value from outer.inner
assert(value == 42)

Function return values#

Destructure directly from function calls:

local function getConfig()
    return { host = "localhost", port = 8080 }
end

local host, port from getConfig()
assert(host == "localhost" and port == 8080)

The function is called once, even when extracting multiple fields:

local callCount = 0
local function counted()
    callCount = callCount + 1
    return { a = callCount, b = callCount }
end

local a, b from counted()
assert(callCount == 1)  -- called once
assert(a == 1 and b == 1)

Conditional expressions#

Destructure from conditional table expressions:

local useDefaults = false
local defaults = { size = 10 }
local custom = { size = 50 }

local size from (useDefaults and defaults or custom)
assert(size == 50)

Motivation#

Lua does not have table destructuring. Extracting multiple fields requires repetitive access expressions.

Repetitive field access#

A common Lua pattern:

-- Lua: manual field extraction
local t = { name = "test", value = 42, enabled = true }
local name = t.name
local value = t.value
local enabled = t.enabled

With from:

-- Lus: destructuring
local t = { name = "test", value = 42, enabled = true }
local name, value, enabled from t

Function parameter patterns#

Extracting options from a configuration table:

-- Lua: verbose extraction
local function configure(options)
    local host = options.host
    local port = options.port
    local timeout = options.timeout
    -- use host, port, timeout
end

With from:

-- Lus: concise extraction
local function configure(options)
    local host, port, timeout from options
    -- use host, port, timeout
end

Module imports#

Extracting functions from a module:

-- Lua: manual extraction
local module = require("mymodule")
local func1 = module.func1
local func2 = module.func2
local func3 = module.func3

With from:

-- Lus: destructured import
local func1, func2, func3 from require("mymodule")