  lua-l archive

• Subject: length operator # for tables with metatables
• From: Leo Razoumov <slonik.az@...>
• Date: Mon, 21 Sep 2009 16:50:05 -0400 (EDT)

```Hi Everyone,
Lua manual defines length operator "#" for tables as follows:
"The length of a table t is defined to be any integer index n such
that t[n] is not nil and t[n+1] is nil; moreover, if t is nil, n
can be zero. For a regular array, with non-nil values from 1 to a
given n, its length is exactly that n, the index of its last value. If
the array has "holes" (that is, nil values between other non-nil
values), then #t can be any of the indices that directly precedes a
nil value (that is, it may consider any such nil value as the end of
the array)."

As one can see from the definition above tbl[#tbl+1] must always be nil.

Unfortunately, it is not the case when table has a metatable as the
following example illustrates:

a={11,22,33}
t= setmetatable({}, {__index=a})
print("#a     = "..#a)
print("#t     = "..#t)
print("t[#t+1]= "..t[#t+1])

The output:

#a     = 3
#t     = 0
t[#t+1]= 11

#t is zero while t, t and t are non-nil. Apparently, this
behavior contradicts just mentioned paragraph from the manual.

The situation can be made even more bizarre if one sets __newindex as well.

a={11,22,33}
t= setmetatable({}, {__index=a,__newindex=a})
print("#a     = "..#a)
print("#t     = "..#t)
t[#t+1] = "AA"
print("a   = ".. a)

The output:

#a     = 3
#t     = 0
a   = AA

Now, instead of appending a new table entry, t[#t+1] = "AA"
overrides the value of a.

Of course, I can always redefine __len meta-method to bring some
sanity to the table.  What worries me, though, is that the default
behavior is so messy.

Am I missing something?

--Leo--

```