lua-users home
lua-l archive

Re: ipairs in Lua 5.3.0-alpha

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


On 2014年8月18日 08:02:01 +0200
Dirk Laurie <dirk.laurie@gmail.com> wrote:
> I don't like it. I don't like Lua 5.3.0-alpha ipairs either.
> 
> What you, and Lua 5.3.0-alpha, have been trying to do
> is to second-guess what semantics ipairs should have
> if a programmer has been tinkering with __len and __index.
That is just one part of my proposal. I basically copied it from
Lua 5.3.0-alpha (incorporating Roberto's idea regarding the
conditional call of luaL_len).
Please also consider the other aspect of my proposal to let
ipairs accept both functions and iterator triplets. This has
nothing to do with __len and __index.
> 
> And Lua 5.3.0-alpha is so prescriptive about it that the
> programmer does not even have the freedom to override
> that guess.
I don't like either that Lua 5.3.0-alpha is not allowing any
customization here. I feel like a standard interface for
"ordinal iteration over whatever object" would really help a
lot of programmers. Removing __ipairs takes away this ability
(IMHO leading to chaos, as elaborated earlier).
> 
> I think _any_ iterator that is metatable-aware must either
> be very explicitly specified (e.g. by __pairs or __ipairs)
> or stashed in the table library, which can have its own tight
> well-specified protocol.
Regarding tables, I would agree that it's a matter of taste
whether to interpret metamethods like __index and __len. I like
the interpretation Lua 5.3.0-alpha uses (disregarding the
previously discussed implementation issues).
But my proposal is mainly not about the interpretation of that
metamethods. It also treats functions in a specific way, which is
rather type-dependent behavior than having to do anything with
metatables.
If you consider my previously posted examples of supercool_ipairs
or the poweriterator C extension it also allows constructs like
this:
Consider a function printcsv, which accepts a sequence:
function printcsv(seq, sep)
 sep = sep or ","
 for i, v in ipairs(seq) do
 if i > 1 then io.stdout:write(sep) end
 io.stdout:write(tostring(v))
 end
 io.stdout:write("\n")
end
Calling this with a raw table is pretty much forward:
printcsv{"a", "b", "c"}
-- prints:
-- a,b,c
printcsv({"a", "b", "c"}, "; ")
-- prints:
-- a; b; c
But it's also possible to call it with a custom iterator function:
do
 local letter = nil
 local function alphabet()
 if letter == nil then
 letter = "a"
 elseif letter == "z" then
 return nil
 else
 letter = string.char(string.byte(letter) + 1)
 end
 return letter
 end
 printcsv(alphabet)
 -- prints:
 -- a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
end
Note that no __index or __len metamethod interpretation happens here.
You might want to ask why ipairs should accept iterator triplets.
Here is one example, why it's cool:
-- let's define a set using a raw table:
set = {apple=true, banana=true, guava=true}
-- now copy the set into an array by
-- making a nested ipairs(pairs(...)) call:
array = {}
for i, v in ipairs(pairs(set)) do array[i] = v end
-- print the array:
for i, v in ipairs(array) do print(i, v) end
-- prints:
-- 1 banana
-- 2 guava
-- 3 apple
-- (order of second column may vary)
All this got nothing to do with guessing what __index and __len mean.
It still works with the following simplified version of the extended
ipairs. The following code doesn't mention __index or __len:
do
 local function ipairsaux_raw(t, i)
 i = i + 1
 local v = rawget(t, i)
 if v then
 return i, v
 else
 return nil
 end
 end
 local function ipairsaux_func(f, i)
 local v, v2, v3, v4, vn = f()
 -- variable arg number requires C implementation
 if v then
 return i + 1, v, v2, v3, v4, vn
 else
 return nil
 end
 end
 local empty = {}
 function ipairs(x, s, i)
 local mt = getmetatable(x) or empty
 local mt_ipairs = rawget(mt, "__ipairs")
 if mt_ipairs ~= nil then
 return mt_ipairs(x)
 elseif type(x) == "function" then
 if s == nil and i == nil then
 return ipairsaux_func, x, 0
 else
 local n = 0
 return function() -- closure not avoidable here
 n = n + 1
 local v, v2, v3, v4, vn = x(s, i)
 -- variable arg number requires C implementation
 if v == nil then
 return nil
 else
 i = v
 return n, v, v2, v3, v4, vn
 end
 end
 end
 else
 return ipairsaux_raw, x, 0
 end
 end
end
Regards
Jan

AltStyle によって変換されたページ (->オリジナル) /