• Subject: Re: Testing for a sequence (was Re: Lua 5.2 Length Operator and tables (bug?)
• From: liam mail <liam.list@...>
• Date: Fri, 20 Apr 2012 01:52:18 +0100

```On 19 April 2012 21:27, Eduardo Ochs <eduardoochs@gmail.com> wrote:
> On Thu, Apr 19, 2012 at 3:17 PM, Dirk Laurie <dirk.laurie@gmail.com> wrote:
>> The definition says "the set of its positive numeric keys is equal to
>> {1..n} for some integer n."  So that test returns false too easily.
>> E.g.
>>
>>> a=table.pack(1,2,3,4)
>>> =IsSequence(a)
>> false
>>
>> Actually, if the purpose is to define when #t and the table library
>> work, the definition should say: "the set of its positive integer
>> numeric keys is empty or equal to {1..n} for some positive integer n."
>>
>
> 0 is an integer, and when n is 0 we have {1,...,n} = {}.
> By the way,
>
>  a = {10, 20, 30, 40, foo="bar",
>       [0]="z", [-2.5]=99, [-250]="!"}
>
> is a sequence - according to the manual =) - but if we do a[6]=60
> the result isn't a sequence anymore.
>
>  Cheers,
>    Eduardo Ochs
>

Here is a table which from what I can tell is a sequence according to
the manual yet once you look at the byte code and how the instructions
are generated you can see why it is not.
Lets take the example of not a sequence from the manual and adjust it[1]

{10, 20, nil, 40}
So it is not a sequence because it is missing an entry for the key 3,

Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> do
>> a={10,20,nil,[3]=30,40}
>> print(#a)
>> end
4

Huh so what is wrong? It looks like a table as it has entries for
1,2,3 and 4 also the implementation being used tells us it has four
entries because it is a sequence, or is it?

> do
>> a={10,20,nil,[3]=30,40}
>> for k,v in pairs(a) do
>> print(k,v)
>> end
>> end
1	10
2	20
4	40

Hmm we explicitly set entry 3 to thirty where did it go? Lets have a
look at the byte code[2]

interactive mode
The first line which ends in '>>' is the end of buffer
"-iend" ends interactive mode
a={10,20,nil,[3]=30,40} >>

.proto
[0012]	00 00 00 00             	;line defined	0	Main
[0016]	00 00 00 00             	;last line	0
[001A]	00                      	;num params
[001B]	01                      	;is vaargs
[001C]	05                      	;max stack size
.text
[001D]	09 00 00 00             	;instruction count 9
[0021]	0B 40 00 02             	;pc[1] OP_NEWTABLE   	R(A) = {}
(arraysize = B, hashsize = C)	A=0 B=4 C=1
[0025]	41 40 00 00             	;pc[2] OP_LOADK      	R(A) = Kst(Bx)	 A=1 Bx=1
[0029]	81 80 00 00             	;pc[3] OP_LOADK      	R(A) = Kst(Bx)	 A=2 Bx=2
[002D]	C4 00 00 00             	;pc[4] OP_LOADNIL    	R(A), R(A+1),
..., R(A+B) = nil	 A=3 B=0
[0031]	0A 00 C1 81             	;pc[5] OP_SETTABLE   	R(A)[RK(B)] =
RK(C)	 A=0 B=259(const[3]) C=260(const[4])
[0035]	01 41 01 00             	;pc[6] OP_LOADK      	R(A) = Kst(Bx)	 A=4 Bx=5
[0039]	24 40 00 02             	;pc[7] OP_SETLIST    	R(A)[(C-1)*50+i]
= R(A+i), 1 <= i <= B	 A=0 B=4 C=1
[003D]	08 00 00 80             	;pc[8] OP_SETTABUP
upvalue[A][RK(B)] = RK(C)	 A=0 B=256(const[0]) C=0
[0041]	1F 00 80 00             	;pc[9] OP_RETURN     	return R(A), ...
,R(A+B-2)	 A=0 B=1 (B=1 no returns)
.const
[0052]	61 00                   	;const[0] = "a"
[0055]	00 00 00 00 00 00 24 40 	;const[1] = 10
[005E]	00 00 00 00 00 00 34 40 	;const[2] = 20
[0067]	00 00 00 00 00 00 08 40 	;const[3] = 3
[0070]	00 00 00 00 00 00 3E 40 	;const[4] = 30
[0079]	00 00 00 00 00 00 44 40 	;const[5] = 40
.nested_proto
.upvalue
[0089]	01 00                   	;upvalue[0] = 	instack=1	idx=0

Now we see:
10 and 20 are loaded in to register 1 and 2
loadnil sets one nil entry into register 3
t[3]=30 is written
40 is loaded into register 4
setlist then loads registers 1,2,3 and 4 into the table overwriting
the explicit entry.

Set list comes after these other assignments and you can see that
reordering has no effect on the entry yet only effects which
instruction loads the fourth constant in to the register [3],

a={10,20,nil,40,[3]=30}>>
...
.text
[001D]	09 00 00 00             	;instruction count 9
[0021]	0B 40 00 02             	;pc[1] OP_NEWTABLE   	R(A) = {}
(arraysize = B, hashsize = C)	A=0 B=4 C=1
[0025]	41 40 00 00             	;pc[2] OP_LOADK      	R(A) = Kst(Bx)	 A=1 Bx=1
[0029]	81 80 00 00             	;pc[3] OP_LOADK      	R(A) = Kst(Bx)	 A=2 Bx=2
[002D]	C4 00 00 00             	;pc[4] OP_LOADNIL    	R(A), R(A+1),
..., R(A+B) = nil	 A=3 B=0
[0031]	01 C1 00 00             	;pc[5] OP_LOADK      	R(A) = Kst(Bx)	 A=4 Bx=3
[0035]	0A 40 41 82             	;pc[6] OP_SETTABLE   	R(A)[RK(B)] =
RK(C)	 A=0 B=260(const[4]) C=261(const[5])
[0039]	24 40 00 02             	;pc[7] OP_SETLIST    	R(A)[(C-1)*50+i]
= R(A+i), 1 <= i <= B	 A=0 B=4 C=1
[003D]	08 00 00 80             	;pc[8] OP_SETTABUP
upvalue[A][RK(B)] = RK(C)	 A=0 B=256(const[0]) C=0
[0041]	1F 00 80 00             	;pc[9] OP_RETURN     	return R(A), ...
,R(A+B-2)	 A=0 B=1 (B=1 no returns)
.const
[0052]	61 00                   	;const[0] = "a"
[0055]	00 00 00 00 00 00 24 40 	;const[1] = 10
[005E]	00 00 00 00 00 00 34 40 	;const[2] = 20
[0067]	00 00 00 00 00 00 44 40 	;const[3] = 40
[0070]	00 00 00 00 00 00 08 40 	;const[4] = 3
[0079]	00 00 00 00 00 00 3E 40 	;const[5] = 30

A little of topic and a corner case I know, but have I missed/misread
a part of the manual which specifies this behaviour?

[1] http://www.lua.org/manual/5.2/manual.html#3.4.6
[2] https://bitbucket.org/liamdevine/lua52_bytecode_dump
[3] This does not seem to be a requirement of the implementation
unless the "finally" from [4] is referring to the constructor order
[4] http://www.lua.org/manual/5.2/manual.html#3.4.8

Liam

```

• References: