Pavel T
Pavel T

Reputation: 13

table size difference. are both examples identical?

tNum={[2]=true , [3]=true,[4]=true, [5]=true ,[6]=true }

#tNum-->0 



tNum={} 
tNum[2]=true 
tNum[3]=true 
tNum[4]=true 
tNum[5]=true 
tNum[6]=true

#tNum-->6 

why such a difference in size? are both examples identical?

Upvotes: 1

Views: 57

Answers (2)

TheAverageCanadian
TheAverageCanadian

Reputation: 337

The issue is that when you define a table as starting at index [2], the length operator breaks because it assumes that tables start at index [1]. The following code works as intended:

tNum = {[1]=false, [2]=true, [3]=true, [4]=true, [5]=true, [6]=true}

#tNum => 6

The odd behaviour is caused because when you initialize an array with tNum={} it initializes by assigning every index to nil, and the first index is [1] (It doesn't actually initialize every value to nil, but it's easier to explain that way). Conversely, when you initialize an array with tNum={[2]=true} you are explicitly telling the array that tNum[1] does not exist and the array begins at index 2. The length calculation breaks when you do this.

For a more thorough explanation, see this section of the lua wiki near the bottom where it explains:

For those that really want their arrays starting at 0, it is not difficult to write the following:

days = {[0]="Sunday", "Monday", "Tuesday", "Wednesday",
        "Thursday", "Friday", "Saturday"}

Now, the first value, "Sunday", is at index 0. That zero does not affect the other fields, but "Monday" naturally goes to index 1, because it is the first list value in the constructor; the other values follow it. Despite this facility, I do not recommend the use of arrays starting at 0 in Lua. Remember that most functions assume that arrays start at index 1, and therefore will not handle such arrays correctly.

The Length operator assumes your array will begin at index [1], and since it does not, it doesn't work correctly.

I hope this was helpful, good luck with your code!

Upvotes: 2

luther
luther

Reputation: 5544

Your two tables are semantically identical, but using # on them is ambiguous. Both 0 and 6 are correct lengths. Here's an abridged version of the docs:

The length operator applied on a table returns a border in that table. A border in a table t is any natural number that satisfies the following condition:

(border == 0 or t[border] ~= nil) and t[border + 1] == nil

A table with exactly one border is called a sequence.

When t is not a sequence, #t can return any of its borders. (The exact one depends on details of the internal representation of the table, which in turn can depend on how the table was populated and the memory addresses of its non-numeric keys.)

This is an example of undefined behavior (UB). (That may not be the right word, because the behavior is partially defined. UB in Lua can't launch nuclear weapons, as it can in C.) Undefined behavior is important, because it gives the devs the freedom to choose the fastest possible algorithm without worrying about what happens when a user violates their assumptions.

To find a length, Lua makes, at most, log n guesses instead of looking at every element to find an unambiguous length. For large arrays, this speeds things up a lot.

Upvotes: 2

Related Questions