Page 3 of 3

Re: Card Game

Posted: Sat Feb 11, 2012 9:18 pm
by tdc5013
Ok. I get that :)

So if ipairs basically does the same job as a basic for loop, why does it exist? Is there a specific function it can apply to, where you'd need to specifically use it, rather than something like the for loop you illustrated?

Re: Card Game

Posted: Sat Feb 11, 2012 9:34 pm
by MarekkPie
I don't see any practical difference; the only thing I can think is perhaps there is a speed difference between regular for and ipairs. I know there is a difference between ipairs and pairs (with pairs being faster), but I am not certain about regular for and ipairs.

Maybe its like how Python programmers say do it the "Python way." ipairs is the Lua way.

Re: Card Game

Posted: Sat Feb 11, 2012 11:07 pm
by Nixola
Kikito, in his tile tutorial, says that the regular for is faster

Re: Card Game

Posted: Sat Feb 11, 2012 11:32 pm
by bartbes
I haven't got the statistics, but yes, it is. ipairs is more idiomatic however, and in general people don't really care about those tiny speed-ups (and you shouldn't, either). There is, however, a difference, ipairs doesn't have to go to #t (with t being the table), since that can include embedded nils.
Example:

Code: Select all

print(#{1, nil, 2}) --> 3
local counter = 0
for i, v in ipairs{1, nil, 2} do
   counter = counter + 1
end
print(counter) --> 1

Re: Card Game

Posted: Sun Feb 12, 2012 12:12 am
by kikito
ipairs, for a while, was going to be removed from Lua 5.2 . Or there were rumors about it; I didn't pay too much attention to them. At the end, it was kept in Lua, and I think that was a good decision.
tdc5013 wrote:So if ipairs basically does the same job as a basic for loop, why does it exist? Is there a specific function it can apply to, where you'd need to specifically use it, rather than something like the for loop you illustrated?
That's a very good question. I thought about it myself, and found a possible explanation.

First of all, ipairs is not exactly like pairs. pairs doesn't give any guarantee about the order in which the elements of the array are parsed. I think right now, it *does* respect the numerical order, but that's an implementation detail; other implementations, like LuaJIT or Lua 5.3, could change the implementation so that it didn't respect the order, and that would still be compatible with the Lua spec. My point is, you can't make the assumption in your code when using pairs.

The obvious conclusion to all this is - ok, I'll use a numeric for then. So, why do I need ipairs?

Well, the answer is, yeah, use a numeric for when you can. But in some occasions you can't. Sometimes you just need an iterator function.

Consider the typical copy function:

Code: Select all

function copy(tbl)
  local result = {}
  for k,v in pairs(tbl) result[k] = v end
  return result
end
As far as I know, in the standard 5.1 Lua, this function works with both hash-like tables and array-like tables - but this is an implementation detail; pairs is not guaranteed to follow the numerical order in keys, so in the next version of Lua, or in an alternative implementation, it might copy the keys in a different order (so it would not generate an array, but a hash). Without ipairs, you would end up needing two different implementations; one for copying arrays, using the numeric for, which is guaranteed to follow the numeric keys, and another one for the rest.

But with ipairs, you can do this:

Code: Select all

function copy(tbl, iterator)
  iterator = iterator or pairs
  local result = {}
  for k,v in iterator(tbl) result[k] = v end
  return result
end
This version of the function accepts a second (optional) parameter called "iterator". By default, it is pairs. But you can set it to ipairs if you want:

Code: Select all

t1 = {1,2,3}
t2 = copy(t1, ipairs)
So, you can get numerical order, if you need it.

Setting the iterator as an optional parameter has another benefit: you can example, create an iterator function that returns only the even members of the array - or the members of the array in reverse order. Or only the members of a hash whose key starts with "a". And the copy function will work with those, too:

Code: Select all

t3 = copy(t1, evenpairs)
t4 = copy(t1, reverseipairs)
t5 = copy(t1, keystartpairs("a"))
So, this is the reason I imagine ipairs exist: When you are developing a function that parses tables, sometimes,you want to let the users of that function specify how they want to parse a table - like with the iterator parameter. And on the other hand, when you are using that function, you may want to have the guarantee that the numeric values are parsed in order. Granted - very rare case. But possible.

At least that is my opinion. I haven't checked that on the Lua mailing list or anything.

Re: Card Game

Posted: Sun Feb 12, 2012 11:05 am
by Robin
What I like about ipairs is that it reduces the "housekeeping" you have to do. Compare:

Code: Select all

for i = 1, #t do
    --.... use i and t[i] here
end
and:

Code: Select all

for i = 1, #t do
    local v = t[i]
    --.... use i and v here
end
to:

Code: Select all

for i, v in ipairs(t) do
    --.... use i and v here
end
In the last, you don't have to index your table or declare an extra local variable all the time, which could distract from the algorithm inside the loop.

Re: Card Game

Posted: Sun Feb 12, 2012 3:32 pm
by tdc5013
Thanks, I understand this now, I think. Slightly different ways of implementation, but if i needed ipairs has a few more functions that For doesn't (even though it's possible to program them with a For loop, it would require a few more lines of code).