lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


My assumption is that Lua has been developed by people who

* are reasonable
* have limited time
* make mistakes

For me, it is reasonable that the length of a table with no positive
integer indices is zero. PiL certainly suggests it; many examples
would not work otherwise. The authors do not want to re-write PiL if a
future version of Lua accidentally returns something other than 0 for
an empty table.

The definition of a sequence in the reference manual has changed
between various versions, but the intent of the sequence has not. It
seems that the reference manual is wrong or unclear for 5.1, and
ambiguous or unclear for 5.2.

The Lua test suite includes the following in nextvar.lua:

    -- test size operation on empty tables
    assert(#{} == 0)
    assert(#{nil} == 0)
    assert(#{nil, nil} == 0)
    assert(#{nil, nil, nil} == 0)
    assert(#{nil, nil, nil, nil} == 0)

which suggests that it is not going to change.

Stephen Irons

On 18 September 2014 01:50,  <polyglot@openmailbox.org> wrote:
> 5.2 REFERENCE MANUAL
>
> "Unless a __len metamethod is given, the length of a table t is only defined
> if the table is a sequence, that is, the set of its positive numeric keys is
> equal to {1..n} for some integer n. In that case, n is its length."
>
> *** Conclusion ***: Without a __len metamethod, an empty table has undefined
> length.
>
> 5.1 REFERENCE MANUAL
>
> "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[1] 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)."
>
> *** Conclusion ***: An empty table (t[1] is nil) may or may not have a
> length of zero.
>
> ===========================================================================
>
> So I'm assuming the following idiomatic code invokes undefined behavior:
>
> a = {}
> a[#a + 1] = 'foo'
>
> As does this code (because of the implicit #a+1):
>
> a = {}
> table.insert(a, 'foo')
>
> ===========================================================================
>
> Yet such code appears repeatedly in PIL (3rd edition), and I haven't
> seen any errata for it:
>
> PAGE 94
>
> threads = {}    -- list of all live threads
> -- [...]
>   table.insert(threads, co)
>
> PAGE 95
>
> local timedout = {}
> -- [...]
> timedout[#timedout + 1] = res
>
> PAGE 99 and PAGE 100
>
> local words = {}
> for w in pairs(counter) do
>   words[#words + 1] = w
> end
>
> PAGE 113 and PAGE 114
>
> local t = {}
> for line in io.lines() do
>   t[#t + 1] = -- [...]
> end
>
> PAGE 115
>
> path = path or {}
> visited = visited or {}
> if visited[curr] then   -- node already visited?
>   return nil            -- no path here
> end
> visited[curr] = true    -- mark node as visited
> path[#path + 1] = curr  -- add it to path
>
> PAGE 129
>
> function Set.tostring (set)
>   local l = {}     -- list to put all elements from the set
>   for e in pairs(set) do
>     l[#l + 1] = e
>   end
>
> PAGE 195
>
> t = {}
> for line in io.lines() do
>    table.insert(t, line)
> end
>
> PAGE 196
>
> a = {}
> for n in pairs(lines) do a[#a + 1] = n end
>
> PAGE 197
>
> local a = {}
> for n in pairs(t) do a[#a + 1] = n end
>
> PAGE 202
>
> local t = {}                    -- table to store the indices
> local i = 0
> while true do
>   i = string.find(s, "\n", i+1) -- find next newline
>   if i == nil then break end
>   t[#t + 1] = i
> end
>
> PAGE 203
>
> words = {}
> for w in string.gmatch(s, "%a+") do
>   words[#words + 1] = w
> end
>
> PAGE 212
>
> function encode (t)
>   local b = {}
>   for k,v in pairs(t) do
>     b[#b + 1] = (escape(k) .. "=" .. escape(v))
>   end
>
> PAGE 218
>
> local a = {}
> a[#a + 1] = -- [...]
>
> PAGE 223
>
> local lines = {}
> -- read the lines in table 'lines'
> for line in io.lines() do lines[#lines + 1] = line end
>
>
>