luaguides

table.maxn (deprecated)

table.maxn(table)

table.maxn returns the largest positive numerical index of a table by walking every entry. It was deprecated in Lua 5.2 and removed from the standard library in Lua 5.3. On stock Lua 5.3 or newer, calling it raises attempt to call a nil value (field 'maxn'). This page documents the 5.1 behavior and shows drop-in replacements for modern Lua.

Parameters

table.maxn takes a single argument:

ParameterTypeDescription
tabletableThe table to inspect. There is no optional index argument; the function scans the whole table, both the array part and the hash part.

Return value

Returns a number: the largest positive integer key found in the table. Negative keys and non-numeric keys are ignored. An empty table, or one with no positive numeric keys, returns 0 (not nil).

Examples

The signatures and outputs below are taken from the Lua 5.1 reference manual and verified against community mirrors.

Basic usage on a dense array

local scores = { 88, 92, 75, 100 }
print(table.maxn(scores))           --> 4
print(scores[table.maxn(scores)])   --> 100

On a contiguous sequence, table.maxn returns the same integer as the length operator. For a dense array like this one, #scores is faster and the obvious choice, but the value of maxn here is the same: 4. The only practical reason to reach for maxn on dense input is legacy code that already uses it everywhere; on a new project, prefer # and stop reading.

Sparse array where # lies

local sparse = { [1] = "a", [2] = "b", [5] = "c" }
print(table.maxn(sparse))   --> 5
print(#sparse)              --> 1   (Lua 5.4); 5.1 left this implementation-defined

The gap between indices 2 and 5 is the whole reason maxn existed. In Lua 5.4 the length operator is pinned to the first contiguous sequence starting at 1, so #sparse is 1 and table.maxn(sparse) is 5.

Mixed keys

local mixed = { name = "alice", [-2] = "neg", [3] = "third" }
print(table.maxn(mixed))   --> 3

Negative and string keys are skipped, so the -2 and name entries are invisible to the scan. Only positive numeric keys count toward the result, which is why the answer is 3 and not -2 even though -2 is the numerically larger integer. The same rule means you cannot trick maxn into returning a non-positive key by stuffing one into the table; the function is hard-coded to ignore anything that is not a positive number.

Stock Lua 5.4 fails at the call site

-- Lua 5.4 (stock interpreter)
print(table.maxn({1, 2, 3}))
-- stdin:2: attempt to call a nil value (field 'maxn')

If your tests run on stock Lua 5.4, any use of table.maxn will break the build the moment it is exercised.

Deprecation and removal

The 5.2 manual flagged table.maxn as deprecated and explicitly told readers to re-implement it in pure Lua if they actually need it. By 5.3 it was gone from the standard table library. Some embedded Lua distributions still ship it for compatibility: Defold, LÖVE 2D (older releases), Solar2D/Corona, the Playdate SDK. Articles that claim a blanket “removed everywhere” are wrong about those environments. For anything that targets stock Lua, assume the call does not exist.

Replacement

For a dense sequence, the length operator is the answer:

local t = {10, 20, 30, 40}
print(#t)        --> 4
print(t[#t])     --> 40

For the rare sparse-array case, a six-line helper does the same job maxn used to do. The function walks the table with pairs, so it sees both the array part and the hash part in a single pass. Drop it at the top of a module and call it in place of table.maxn anywhere that 5.1-style sparse semantics are still required by old code you are stuck with.

local function maxn(t)
  local n = 0
  for k in pairs(t) do
    if type(k) == "number" and k > n then n = k end
  end
  return n
end

print(maxn({10, 20, 30}))           --> 3
print(maxn({name = "bob", 1, 2}))   --> 2
print(maxn({}))                     --> 0

The helper iterates with pairs() rather than ipairs(), so it sees hash-part keys as well as array-part indices. For userdata, or tables without an __len metamethod, rawlen() is the matching way to query the raw length. When you need to move elements around in a sequence, table.move() is the 5.3+ replacement for the older array-shifting patterns people used to write around maxn.

Common pitfalls

  • Returns 0, not nil, on empty input. Code that does if maxn(t) then ... is correct; so is if maxn(t) > 0 then .... Treating 0 as “missing” is the usual bug.
  • Linear time. The function walks every entry. Do not call it inside a tight loop over the same table; cache the result or restructure the data.
  • Ignores __len and __index. table.maxn uses pairs semantics, so a metatable’s metamethods never fire. If you need that behavior, write the loop yourself and invoke the metamethod directly.
  • Not the same as table.getn. That older Lua 4 / 5.0 alias returned the length of the sequence (the same thing # does). maxn answered a different question and was kept around because the answer was useful for sparse data.

See also