lua-users home
lua-l archive

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


On Tue, 19 Aug 2014 09:06:40 -0300
Roberto Ierusalimschy <roberto@inf.puc-rio.br> wrote:

> > This is why "PUC approval" and incorporation into Lua 5.3 would really
> > help here.
> 
> I really do not think that ipairs + __ipairs is a good generic iterator
> interface.

For semantic reasons or due to implementation issues?


> That was never the intention when we created __ipairs.

Yes, since it only worked on raw tables in Lua 5.1, I can follow you
here. I wonder why __ipairs was introduced in Lua 5.2 in the first
place then?


> Among other problems,

Would you like to share with us these other problems that you see? I
would like to understand all possible implications.


> it forces an object to have only one "true" iterator; it
> is too "object" centric. (For instance, how do you fit the result from
> "string.gmatch" into that shoe? Or io.lines, with all its variations?)
> [...]

Here, I would like to note that my proposal consisted of three parts:

* keep the __ipairs metamethod
* extend ipairs to accept iterator functions
* extend ipairs to accept iterator triplets

Your critics apply to the first point only. If you see __ipairs as
too object centric, then I agree: It should be removed.


But extending ipairs to accept iterator functions (and maybe triplets)
doesn't mean that a value has only one way to iterate over it. Consider:

* sql:query(...):rows_with_named_columns()
* sql:query(...):rows_with_numeric_columns()
* sql:query(...):first_ten_rows()
* sql:query(...):rows_reversed()

Extending ipairs in such way that it accepts iterator functions
(and/or triplets) would mean that we can easiliy create a function
which accepts either one of the above iterators but also a literal
like {row1, row2, row3}:

* printrows(sql:query(...):rows_with_named_columns())
* printrows(sql:query(...):rows_with_numeric_columns())
* printrows{row1, row2, row3}


> I think Lua already has a good generic iterator, in the form of a
> function returning values, [...]

Exactly! This is why there is no problem to provide a default behavior
when passing such an iterator function to ipairs.


Now, of course, you could argue that since Lua 5.3 doesn't need to
provide any sort of __ipairs interface, each library could implement
whatever ipairs function (that accepts functions as argument) on its
own. I would unfortunately have to agree here. But I still think that
extending ipairs in such way to accept functions (and possibly creating
an easy to use API interface for ordinal iteration on functions AND
tables) would encourage library programmers to create interfaces that
do not distinguish between (function) iterators and (table) sequences.


Consider:

function printcsv(seq)
  if type(seq) == "function" then
    local first = true
    for v in seq() do
      if not first then
        io.stdout:write(",")
      else
        first = false
      end
      io.stdout:write(v)
    end
  else
    for i, v in ipairs(seq) do
      if i > 1 then io.stdout:write(",") end
      io.stdout:write(v)
    end
  end
  io.stdout:write("\n")
end

versus:

require("fixed_ipairs")
function printcsv(seq)
  for i, v in fixed_ipairs(seq) do
    if i > 1 then io.stdout:write(",") end
    io.stdout:write(v)
  end
  io.stdout:write("\n")
end

versus:

function printcsv(seq)
  for i, v in ipairs(seq) do
    if i > 1 then io.stdout:write(",") end
    io.stdout:write(v)
  end
  io.stdout:write("\n")
end


Regards
Jan