Lua gotcha is not this.
There’s no difference in “nil” vs “exists but nil”, because nil means “doesn’t exist” by definition. The gotcha is in # operator which when applied to a table may return incorrect “length” of its array part if it has holes in it. For example #{1,2,nil,4} can be 2 or 4.
It happens because Lua arrays are not “just dicts with integer keys” as someone said above. A lua table impl has two parts: one for dict and one for array. # basically returns “impl(t).array.length”. This array part gets populated and depopulated heuristically creating non-determinated outcomes for #.
This has nothing to do with bounds or existence tests. “Really null” is an attempt to have nil in an array, which Lua doesn’t by design.