[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: ipairs in Lua 5.3.0-alpha
- From: Jan Behrens <jbe-lua-l@...>
- Date: Mon, 18 Aug 2014 13:18:38 +0200
On Mon, 18 Aug 2014 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
- References:
- Speed of # operator (Was: ipairs in Lua 5.3.0-alpha), Dirk Laurie
- Re: ipairs in Lua 5.3.0-alpha, Jan Behrens
- Re: ipairs in Lua 5.3.0-alpha, Roberto Ierusalimschy
- Re: ipairs in Lua 5.3.0-alpha, Jan Behrens
- Re: ipairs in Lua 5.3.0-alpha, Jan Behrens
- Re: ipairs in Lua 5.3.0-alpha, Roberto Ierusalimschy
- Re: ipairs in Lua 5.3.0-alpha, Jan Behrens
- Re: ipairs in Lua 5.3.0-alpha, Doug Currie
- Re: ipairs in Lua 5.3.0-alpha, Coda Highland
- Re: ipairs in Lua 5.3.0-alpha, Jan Behrens
- Re: ipairs in Lua 5.3.0-alpha, Andrew Starks
- Re: ipairs in Lua 5.3.0-alpha, Jan Behrens
- Re: ipairs in Lua 5.3.0-alpha, Jan Behrens
- Re: ipairs in Lua 5.3.0-alpha, Jan Behrens
- Re: ipairs in Lua 5.3.0-alpha, Dirk Laurie