lua-users home
lua-l archive

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


On Wed, 13 Aug 2014 22:33:23 +0200
Jan Behrens <jbe-lua-l@public-software-group.org> wrote:

> By principle, however, it is not possible to reduce this overhead,
> because the way the for-loop works in Lua, we may only pass one Lua
> value (the second value of the triplet) as state. Unless luaB_ipairs
> creates either a closure or a table that contains the length
> information (and thus the termination point of the iteration), we
> cannot remember the length and will have to redetermine it during every
> iteration step. Creating tables or closures, however, would have an
> even greater perfomance impact.

On Fri, 15 Aug 2014 03:07:16 +0200
Jan Behrens <jbe-lua-l@public-software-group.org> wrote:

> Sorry to bring this up... but... consequently, maybe the global ipairs
> function should be completely removed and replaced by a language
> construct in the long term?
> 
> Consider:
> 
> for v = t[i] do
>   print(i, v)
> end

I just came up with a better idea, which only introduces minimal
changes into the language, but allows a removal of the __ipairs
metamethod, yet avoiding re-evaluating the length for every
iteration step: adjusting Lua's for-statement in such way that more
than one state variable can be passed.

This - at first - looks like it would break downward compatibility.
But it does not.

Lua 5.3.0-alpha works like this:

============================================================
function lua53alpha_for(args)
  local f, s, var = table.unpack(args.explist)
  local block     = args.block
  while true do
    local results = {f(s, var)}
    if results[1] == nil then break end
    var = results[1]
    block(table.unpack(results))
  end
end

do
  local function lua53alpha_ipairs_aux(t, i)
    print("Evaluating length here!")
    if i < #t then
      i = i + 1
      return i, t[i]
    else
      return nil
    end
  end
  function lua53alpha_ipairs(t)
    return lua53alpha_ipairs_aux, t, 0
  end
end

t = {"a", "b", "c"}

lua53alpha_for{explist = {lua53alpha_ipairs(t)}, block = function(i, v)
  print(i, v)
end}
-- results in:
-- Evaluating length here!
-- 1   a
-- Evaluating length here!
-- 2   b
-- Evaluating length here!
-- 3   c
-- Evaluating length here!
============================================================

NOTE: Of course, Lua internally doesn't create tables here. I just need
      to create tables in the above example code to demonstrate the way
      Lua works. It should be understood as pseudocode.

Because Lua 5.3.0-alpha can only deal with one state variable, it needs
to re-evaluate the length in the "lua53alpha_ipairs_aux" function
(calling "luaL_len" in "ipairsaux" in baselib.c).

But why don't we allow more than one state variable?

Consider the following (pseudo)code:

============================================================
function alternate_for(args)
  local f            = args.explist[1]
  local statecount   = math.max(1, #args.explist - 2)
  local s1_s2_sn_var = {}
  local block        = args.block
  for i = 1, statecount+1 do
    s1_s2_sn_var[i] = args.explist[i+1]
  end
  while true do
    local results = {f(table.unpack(s1_s2_sn_var))}
    if results[1] == nil then break end
    s1_s2_sn_var[statecount+1] = results[1]
    block(table.unpack(results))
  end
end

do
  local function alternate_ipairs_aux(t, maxn, i)
    if i < maxn then
      i = i + 1
      return i, t[i]
    else
      return nil
    end
  end
  function alternate_ipairs(t)
    print("Evaluating length here!")
    return alternate_ipairs_aux, t, #t, 0  -- not a triplet but a quadruple
  end
end

t = {"a", "b", "c"}

alternate_for{explist = {alternate_ipairs(t)}, block = function(i, v)
  print(i, v)
end}
-- results in:
-- Evaluating length here!
-- 1   a
-- 2   b
-- 3   c

-- alternate_for is backwards compatible to lua53alpha_for:

alternate_for{explist = {lua53alpha_ipairs(t)}, block = function(i, v)
  print(i, v)
end}
-- results in:
-- Evaluating length here!
-- 1   a
-- Evaluating length here!
-- 2   b
-- Evaluating length here!
-- 3   c
-- Evaluating length here!
============================================================


I'd like to know if this is feasible for Lua 5.3.


Regards
Jan Behrens