lua-users home
lua-l archive

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


On 21 January 2013 15:41, John Hind <john.hind@zen.co.uk> wrote:
> The behaviour of table.insert and table.delete in Lua 5.2.1 is odd and not
> fully documented.
>
> table.remove bounds checks the 'pos' parameter and silently does nothing if
> pos is less than 1 or greater than #.
>
> table.insert on the other hand does no bounds checking and will happily
> insert element -1, element 100000 etc. sometimes unnecessarily moving
> elements.
>
> So, code like this does not produce reasonably expected results:
>
> t = {"salt"}                 -- {[1] = "salt"}
> table.insert(t, -10, "test") -- {[-10] = "test"; [2] = "salt"}
> table.remove(t, -10)         -- {[-10] = "test"; [2] = "salt"}
> table.remove(t, 2)           -- {[-10] = "test"; [2] = "salt"}
> table.insert(t, 1000, "over")-- {[-10] = "test"; [2] = "salt"; [1000] =
> "over"}
> table.remove(t, 1000)        -- {[-10] = "test"; [2] = "salt"; [1000] =
> "over"}
> table.insert(t, 1000, "big") -- {[-10] = "test"; [2] = "salt"; [1000] =
> "big"}
>
> Why has "salt" been moved unnecessarily after the first 'insert'?
>
> Why will 'remove' not remove some elements 'insert' was happy to insert?
>
> Why did the last 'remove' not move the original element 1000 to 1001?
>
> Suggestion:
>
> Use an 'index' rather than 'pos' similar to 'select' in Lua or the C API
> stack. So a negative index counts back from -1 = #. After resolving negative
> indexes, an index out of the range (1 <= index <= #) for remove, or (1 <=
> index <= (# + 1)) for insert, should either cause an error panic or should
> saturate the index at 1 or the upper limit.
>
> Or:
>
> table.insert should still insert "outliers", but should not move "main
> sequence" elements when it does. table.remove should remove outliers as well
> as "main sequence" elements. But inserting an "outlier" which was already
> present would still present an anomaly in this scheme.
>
> I like the first suggestion best, with the error panic. At the very least,
> table.insert should not move elements unnecessarily.
>
>
>

Table functions operate on arrays[1][2] (otherwise called lists in the
manual IIRC) or in 5.2 have a special metamethod[3].  I therefore
would consider invalid operations on an array or not being passed an
array as undefined behaviour.

>>Why has "salt" been moved unnecessarily after the first 'insert'?

It was given an array with one entry (ie index 1) and asked to insert
an invalid index (-10) before it, therefore it moved index the current
# entry to #+1.

>>Why will 'remove' not remove some elements 'insert' was happy to insert?
>>Why did the last 'remove' not move the original element 1000 to 1001?

Remove works on arrays and it is not given an array.

>>At the very least, table.insert should not move elements unnecessarily.

And yet, I could say a programmer should not invoke undefined
behaviour as there be dragons :)

Propagating an error could be a possibility yet the undefined then
becomes defined.

[1] PiL 1st Edition,  19 The Table Library
"The table library comprises auxiliary functions to manipulate tables
as arrays. One of its main roles is to give a reasonable meaning for
the size of an array in Lua. It also provides functions to insert and
remove elements from lists and to sort the elements of an array."

[2]PiL 2nd,  19 The Table Library and 3rd Edition,  20 The Table Library
"The table library comprises auxiliary function to manipulate tables
as arrays. It provides functions to insert and remove elements from
lists, to sort the elements of an array, and to concatenate all
strings in an array"

[3] 5.2 Manual,  6.5 Table Manipulation
"Remember that, whenever an operation needs the length of a table, the
table should be a proper sequence or have a __len metamethod"

--Liam