🎓 A1Learner
🔍
0 of 52 lessons completed

Lua Closures for Privacy

Private state in Lua is a local variable that only functions returned from the same factory call can read or change. Code outside the factory cannot reach that variable directly.

Only returned functions reach the balance

The factory returns a deposit function and a balance function. Code outside the factory cannot see the balance variable.

local function make_account()
  local balance = 0
  local function deposit(amount)
    balance = balance + amount
  end
  local function get_balance()
    return balance
  end
  return deposit, get_balance
end
local deposit, get_balance = make_account()
print(get_balance())
deposit(50)
print(get_balance())
print(balance)

Two accounts keep separate private balances

Each factory call makes its own balance. A deposit into one account leaves the other unchanged.

local function make_account()
  local balance = 0
  local function deposit(amount)
    balance = balance + amount
  end
  local function get_balance()
    return balance
  end
  return deposit, get_balance
end
local a_deposit, a_balance = make_account()
local b_deposit, b_balance = make_account()
a_deposit(30)
b_deposit(80)
print(a_balance())
print(b_balance())
a_deposit(20)
print(a_balance())
print(b_balance())

A guard can refuse a bad withdrawal

The withdraw function checks the balance first. A withdrawal larger than the balance changes nothing.

local function make_account()
  local balance = 0
  local function deposit(amount)
    balance = balance + amount
  end
  local function withdraw(amount)
    if amount <= balance then
      balance = balance - amount
    end
  end
  local function get_balance()
    return balance
  end
  return deposit, withdraw, get_balance
end
local deposit, withdraw, get_balance = make_account()
deposit(100)
withdraw(150)
print(get_balance())
withdraw(40)
print(get_balance())

Example

local function make_account()
  local balance = 0
  local function deposit(amount)
    balance = balance + amount
  end
  local function withdraw(amount)
    if amount <= balance then
      balance = balance - amount
    end
  end
  local function get_balance()
    return balance
  end
  return deposit, withdraw, get_balance
end
local a_deposit, a_withdraw, a_balance = make_account()
local b_deposit, b_withdraw, b_balance = make_account()
a_deposit(200)
a_withdraw(250)
print(a_balance())
a_withdraw(70)
print(a_balance())
b_deposit(50)
b_withdraw(80)
print(b_balance())
b_deposit(20)
print(b_balance())

Key points

  • Private variable: a local variable that code outside its factory cannot reach directly.
  • Returned access: a returned function is the only path to the private variable.
  • Shared private state: two functions returned together use the same private variable.
  • Guard: a check inside a returned function that can refuse a change to the private variable.
  • Separate accounts: each factory call makes a new private variable for its own account.

In this example, the factory returns deposit, withdraw, and balance functions that share one private balance. Account a deposits 200, refuses a withdrawal of 250, then withdraws 70 to reach 130. Account b deposits 50, refuses a withdrawal of 80, then deposits 20 to reach 70.

Note

privacy here comes from local scope, not from a special private keyword.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

Which statement about the balance inside make_account is true?