[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: "Implicit" pairs, was Re: GUI interface style query
- From: Rici Lake <lua@...>
- Date: Mon, 1 Nov 2004 10:21:58 -0500
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?!?