• Subject: User-definable table length
• From: Egor Skriptunoff <egor.skriptunoff@...>
• Date: Sat, 17 Mar 2018 15:16:04 +0300

Hi!

The following idea already occurred several times on this mailing list.
We are solving not the problem we have.
We actually need neither nils in tables nor array data type.
All we need is USER-DEFINABLE TABLE LENGTH.
As I can see, a lot of people are still using old approach of user-defined
length, they store table length in field "n".
That old approach is not bad, and my suggestion is to improve it a bit.

Let's each table has property "user-specified length".
This property is NOT a table key.

If "user-specified length" is set to nil,
then #t returns usual (5.3) table length.
If "user-specified length" is set to non-nil value,
this value is returned by #t.

You can set "user-specified length" by assigning new value to #t.
You can switch the table back to usual (5.3) mode by assigning nil to #t.

t = {11, 22, 33}
assert(#t == 3)
#t = 42
assert(#t == 42)
#t = nil
assert(#t == 3)
#t = #t + 1
t[#t] = 44
assert(#t == 4)
t[4] = nil
assert(#t == 4)

For backward compatibility, usual table constructor {...} creates a table
with "user-specified length" set to nil.
New syntax {...#} is used for constructing a table
with its "user-specified length" set to actual data length.

local function f()
return nil, nil
end

t = { f() }
assert(#t == 0)

t = { f() #}
assert(#t == 2)

t = { "one", nil, foo=nil #}
assert(#t == 2)

function g(...)
t = { ... #}
assert(#t == select('#', ...))
end

Probably, syntax {...#} is not nice.
I just don't have a good idea about new syntax.

More details:
1) Setting new "user-specified length" does not remove anything
from the table.
2) "user-specified length" must be changed automatically by some
standard "table"-library functions according to their semantics
(only when "user-specified length" is a number).
3) When user grows/shrinks array manually, he/she must modify
"user-specified length" manually.
Old idiom for appending a new value to an array
t[#t + 1] = next_value
should be replaced with new idiom:
#t = #t + 1
t[#t] = next_value

4) New metamethod __setlen is needed.

I guess this improvement of old good "t.n" would solve most of the problems
related to arrays, tuples, nils in tables, and strange array length algo.

-- Egor