lua-users home
lua-l archive

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


On Wed, Aug 24, 2016 at 6:07 PM, Daurnimator <quae@daurnimator.com> wrote:
> On 25 August 2016 at 10:56, Patrick Donnelly <batrick@batbytes.com> wrote:
>> So as far as I've seen, most C code uses the Lua manual's example code
>> structure to iterate tables. Namely:
>>
>> lua_pushnil(L);
>> while (lua_next(L, idx) != 0) {
>>   /* code here */
>>   lua_pop(L, 1); /* pop value */
>> }
>>
>> This structure goes back to the Lua 4.0 manual [1].
>>
>> I noticed that the C for loop results in a more natural construction:
>>
>> for (lua_pushnil(L); lua_next(L, idx); lua_pop(L, 1)) {
>>    /* code here always has the key/value pair on the stack */
>> }
>>
>> One of the advantages I see is that the for loop code block must
>> follow good stack discipline (not leaving anything on the stack or
>> incidentally removing the value) because the lua_pop must always pop
>> the value. For example, this code is not very flexible to future
>> changes:
>>
>> lua_pushnil(L);
>> while (lua_next(L, idx)) {
>>   lua_pushboolean(L, 1);
>>   lua_rawset(L, someidx); /* value removed by rawset */
>> }
>>
>> So does anyone use the for loop construct? I appreciate the manual
>> version is more clear in how it works but it is taken as the idiomatic
>> way to iterate tables. (In fact, the Lua source code uses that style
>> in the base libraries.)
>>
>> [1] https://www.lua.org/manual/4.0/manual.html#5.12
>>
>> --
>> Patrick Donnelly
>>
>
> Neither of those styles take into account __pairs. If we want to
> spread new idioms, I suggest we pick one that will respect __pairs.
>
> That said, lua_pop is really just lua_gettop + lua_settop. To reduce
> the need for stack discipline we can just use settop instead, perhaps
> something like:
>
> for (int base_idx = (lua_pushnil(L), lua_gettop(L)); lua_next(L, idx);
> lua_settop(L, baseidx))
>
> I'm not sure if this is correct (will C evaluate the pushnil/gettop in
> a defined order?).
>

Yes, the comma operator defines a sequence point, so it's guaranteed
to evaluate left-to-right. (The syntactic commas in function lists,
however, do not define sequence points, IIRC.)

/s/ Adam