Serialization and deserialization are common practices on Roblox.
This is a way to handle nil in Luau when you need to serialize data (DataStores/JSON) or just in general.
Standard tables delete keys assigned to nil. By using a holder object (the NIL_SENTINEL string), you provide a placeholder that retains the array index during JSON encoding, without excluding the entry.
The length operator # is unreliable in arrays with holes. Storing PackedInit.n ensures that we know exactly how many elements exist, even if the last values are nil.
Using table.unpack(result, 1, packedTable.n) is basically the main ingredient to this. Providing the third argument forces Luau to unpack the full range. Without it, the unpack would truncate at the first nil it hits.
Unlike using tables or newproxy as sentinels, a string sentinel survives HttpService:JSONEncode. This makes it viable for saving data or sending it across RemoteEvents.
However, RemoteEvents encodes data on its own (binary serialization), so it’s up to whatever you’re using it for.
If a legitimate data value could ever be the string “NIL_SENTINEL”, the decode would incorrectly treat it as nil, which can be solved with type scoping, GUIDs, and null terminators.
local HttpService = game:GetService("HttpService")
local NIL_SENTINEL = "__NIL_SENTINEL__"
local InitList = {"a", "b", "c"}
local function EncodeCreationEntity(Entity)
local PackedInit = {}
for i, key in ipairs(InitList) do
PackedInit[i] = (Entity[key] == nil) and NIL_SENTINEL or Entity[key]
end
PackedInit.n = #InitList
return { InitData = PackedInit }
end
local function UnpackEntity(packedTable)
local result = {}
for i = 1, packedTable.n do
result[i] = (packedTable[i] == NIL_SENTINEL) and nil or packedTable[i]
end
return table.unpack(result, 1, packedTable.n)
end
local encodedEntity = EncodeCreationEntity({
a = 1,
b = nil,
c = 3,
})
local serialized = HttpService:JSONEncode(encodedEntity)
local deserialized = HttpService:JSONDecode(serialized)
print(UnpackEntity(deserialized.InitData)) -- 1 nil 3
This was a pretty big discussion back when Lua was in its early stages. You can read up on some older wikis on the official page to understand it further.