[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: RE: '__iter', yet again!
- From: "John Hind" <john.hind@...>
- Date: Thu, 17 Dec 2009 09:35:51 -0000
That is a cleaver solution - thanks for sharing!
It is essentially the same as the one discussed earlier by LHdeF, except
that you generalise it using the double-indexing trick. Presumably you have
further mechanisms to maintain the integrity of the double-index which could
get quite complex (for example, if you have a dictionary-like collection and
allow selective deletion in the Generic For, you'd need a way of getting to
the string key from the numeric key).
Also you have to compact the numeric index for random deletions to avoid
holes developing? This could get expensive!
-----Original Message-----
From: lua-bounces@bazar2.conectiva.com.br
[mailto:lua-bounces@bazar2.conectiva.com.br] On Behalf Of Ronald Lamprecht
Sent: 16 December 2009 23:09
To: Lua list
Subject: Re: '__iter', yet again!
Hi,
John Hind wrote:
> I am trying to write an object oriented library in which you can have
> objects for which the following is valid:
>
> for v in obj do ... end
>
> Using the __call metamethod you can easily get to:
>
> for v in obj() do ... end
>
> But the redundant parenthesis rankles.
In most cases you can simply eliminate the need of the parenthesis by
double indexing the container object. I noticed this usefull concept
when reengineering the Lua API for our project two years ago. I
implemented a set like container called "group" supporting joins,
intersections, etc. The for loop is as simple as:
for obj in group do obj:toggle() end
The implemention is very simple and does not require any Lua change at all.
In OO you can rely on objects having a unique id. You just need to store
the objects twice in your container - once at their regular index and
once at their id used as index. The "group" is in fact Lua table based
and stores the objects at standard numerical indices, which makes the
concepts implementation very straight forward.
The __call has no need to store the iteration state, as the last object
with its unique id fulfills this purpose:
static int iteratorGroup(lua_State *L) {
// generic for loop iterator function
// var_1 = _f(_s, _var) with _var == nil on first access, var_1 ==
nil on end
// on stack: group, _s, _var
if (!(is_group(L, 1)))
throwLuaError(L, "Group: iterator first arg not a group");
lua_getmetatable(L, 1);
int size = lua_objlen(L, -1);
if (lua_isnil(L, 3)) { // first iterator loop access
if (size == 0) { // an empty group
lua_pushnil(L);
return 1;
} else {
lua_rawgeti(L, -1, 1); // get the first object
return 1;
}
} else {
lua_pushvalue(L, 3); // copy last object as key
lua_rawget(L, -2); // get last index
int i = lua_tointeger(L, -1);
lua_rawgeti(L, -2, ++i); // get next object
return 1;
}
}
Be aware that the implementation depends on the containers index usage
and the object id's nature. But the concept can easily been modified for
other index and id types.
This implementation is up and running and is meanwhile being used by
multiple ten thousand lines of code.
>> you are
>> wrongfully introducing object oriented concepts in a language that is
>> not OO.
>
> I was about to write this, but you were faster. Thanks,
I agree that in most cases it is preferable not to reveal underlying OO
technology in the Lua part to its full extend. A simple object based API
that hides complex concepts like inheritance can be more suitable.
Greets,
Ronald