lua-users home
lua-l archive

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


If I understand correctly, the syntax:

  for <var1> [,<varlist>] in <exprlist> do <chunk> end

is staying; the change would be to the semantics of <exprlist>.
(I separated out <var1> so that the exposition below would work.)
Consequently, the change is basically to the VM, not to the parser.

The current behaviour is roughly as follows:
(#foo is used here for an "invisible local"; the names I use
are different from the ones in the reference manual because I
always find "state" to be confusing. #G represents the C-visible
global environment.)

-- 1: evaluate the exprlist
  local #iterfn, #object, #current = <exprlist>
-- 2: special case tables
  if type(#iterfn) == "table" then
    #iterfn, #object = #G.next, #iterfn
  end
-- 3: Loop
  while true do
    local <var1>, <varlist> = #iterfn(#object, #current)
    #current = <var1>
    if #current == nil then break end
    <chunk>
  end

I believe the proposal is to simply drop step 2 of the above.

Here is an alternative for step 2, which permits the definition of
a default iteration style for objects with metatables (as well as
some options for objects without metatables, see below).

-- 1: evaluate the exprlist
  local #iterfn, ... = <exprlist>
  local #object, #current
-- 2: Find an iterator
  do
    local #pairs
    if type(#iterfn) ~= "function" then
      if getmetatable(#iterfn) then
        #pairs = getmetatable(#iterfn).__pairs
      end
      if not #pairs then
        #pairs = #G.__pairsByType[type(#iterfn)] -- * see below
      end
    end
    if #pairs then
        #iterfn, #object, #current = #pairs(#iterfn, ...)
      else
        #iterfn, #object, #current = #iterfn, ...
    end
  end
-- 3: Loop
  while true do
    local <var1>, <varlist> = #iterfn(#object, #current)
    #current = <var1>
    if #current == nil then break end
    <chunk>
  end

The global __pairsByType might or might not be exposed (and in the
latter case it might be virtual).

Some plausible implementations might include:

  function __pairsByType.table(t, ...)
    if getmetatable(t) and getmetatable(t).__call then
      return t, ...
    else
      return #G.next, t, ...
    end
  end

  function __pairsByType.userdata(t, ...)
    if getmetatable(t) and getmetatable(t).__call then
      return t, ...
    end
  end

These allow tables and userdata with __call metamethods (and
without __pairs metamethods) to work as functions.


  function __pairsByType.string(t, pat)
    return string.gfind(t, pat or ".")
  end


This allows the usage:

  for char in string do ... end

and also "elided gfind" usages like:

  for word in string, "[%S]+" do ... end

  -- (Illustrative only)
  function upranger(increment)
    return function(limit, current)
      current = current + increment
      if current <= limit then return current end
    end
  end

  function downranger(increment)
    return function(limit, current)
      current = current + increment
      if current >= limit then return current end
    end
  end

  function __pairsByType.number(from, upto, by)
    if by >= 0 then
      return upranger(by), upto, from
    else
      return downranger(by), upto, from
    end
end

This allows a single for syntax to also do numeric ranges:

  for i in 1, 10 do ... end
  for i in 10, 1, -3 do ... end

but as expressed above is considerably less efficient than the
current numeric for loop.



On 1-Nov-04, at 8:54 AM, Ashwin Hirschi wrote:


How deprecated is the 'implicit pairs()' case anyways?  I'm using it
throughout - should I change my habits?  0:)

Yes. There is a good chance of it not being present in 5.1 final.

I will *not* be pleased if it goes.

Why drop something that's elegant and well-defined?!?