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
| Parameter | Type | Required | Description |
|---|---|---|---|
v | any | Yes | The 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:
| Function | What it skips | Purpose |
|---|---|---|
rawget(t, k) | __index metamethod | Read a key without triggering __index |
rawset(t, k, v) | __newindex metamethod | Write a key without triggering __newindex |
rawlen(v) | __len metamethod | Get 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__eqref-rawget— raw table key read bypassing__indexref-rawset— raw table key write bypassing__newindex- Lua Metatables — where
__lenand other metamethods are defined - Tables Intro — sequence part and array semantics in Lua tables