luaguides

rawlen

rawlen(v)

rawlen(v) returns the length of a table or string without invoking the __len metamethod. It reads the length field directly from the value, bypassing any custom length behavior defined via metatable.

Parameters

ParameterTypeRequiredDescription
vanyYesThe value to measure. Typically a table or string.

Return Value

Returns a number: the length of the sequence part of a table, the byte count of a string, or 0 for other types.

Behavior

For tables, rawlen returns the length of the sequence part — the count of consecutive integer keys starting from 1. This is the same result #t gives when the table has no __len metamethod.

For strings, it returns the number of bytes. For other types (numbers, booleans, userdata, etc.), it returns 0.

The critical distinction from the # operator: rawlen never calls the __len metamethod. If a table has a custom __len defined via metatable, #t invokes that metamethod, while rawlen(t) ignores it entirely and returns the raw sequence length.

Examples

Basic sequence length

The simplest use of rawlen is getting the length of a regular array-style table. This behaves exactly like the # operator when no metamethods are involved — the function counts the number of consecutive integer keys starting from 1.

local t = {10, 20, 30}
print(rawlen(t))  -- 3

Bypassing a custom __len metamethod

The real value of rawlen shows up when a table has been given a custom __len metamethod that reports a different length. Libraries and frameworks sometimes override __len to return a logical count or a cached value that differs from the actual number of array elements. The # operator will respect that override, but rawlen gives you the ground truth — how many consecutive integer keys the table physically holds.

local t = setmetatable({1, 2, 3, 4, 5}, {
    __len = function() return 100 end
})

print(#t)        -- 100 (calls the __len metamethod)
print(rawlen(t)) -- 5   (ignores __len, returns actual sequence length)

String byte length

When you pass a string to rawlen, it returns the number of bytes — the same value you would get from #s. This is useful in contexts where you are writing generic code that handles both tables and strings, and you want a consistent length function that works across both types without worrying about which one you have.

local s = "hello world"
print(rawlen(s)) -- 11

rawlen also handles strings containing embedded null bytes correctly — the length is the total byte count, not the position of the first \0. This matters when you are working with binary data stored in strings, which is common in Lua networking and file I/O. A null byte in a Lua string is just another byte — it does not terminate the string the way it would in C — and rawlen reflects the full allocation.

local s = "abc\0def"
print(rawlen(s)) -- 7 (not 3)
print(#s)        -- 7 (same behavior as #)

Non-table types

For any value that is not a table or a string — numbers, booleans, nil, functions, userdata — rawlen returns 0. It does not error, so you can safely call it on any Lua value without type-checking first. This makes it safe to use in generic utility functions that accept arbitrary inputs.

print(rawlen(42))       -- 0
print(rawlen(true))     -- 0
print(rawlen(nil))      -- 0

When to Use rawlen

The main use case is when you’re working with tables that have a __len metamethod, but you need the actual sequence length regardless of how length is defined. This comes up in:

  • Serialization code that needs reliable array length, not a custom representation
  • Debugging and inspection where metamethods might distort what you’d expect
  • Low-level library code that must not trigger side effects from length queries

Here is a serializer that uses rawlen to get the true array length, ignoring any custom __len that a table might define:

local function serialize_array(t)
    local parts = {}
    local n = rawlen(t)  -- real length, no metamethods
    for i = 1, n do
        parts[i] = tostring(t[i])
    end
    return "[" .. table.concat(parts, ", ") .. "]"
end

rawlen and the raw access pattern

Lua has three functions for raw (non-metamethod) table access:

FunctionWhat it skipsPurpose
rawget(t, k)__index metamethodRead a key without triggering __index
rawset(t, k, v)__newindex metamethodWrite a key without triggering __newindex
rawlen(v)__len metamethodGet length without triggering __len

Together they let you work with tables at the data structure level, ignoring any behavioral overlays from metatables.

See Also

  • ref-rawequal — raw equality check bypassing __eq
  • ref-rawget — raw table key read bypassing __index
  • ref-rawset — raw table key write bypassing __newindex
  • Lua Metatables — where __len and other metamethods are defined
  • Tables Intro — sequence part and array semantics in Lua tables