[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: default LUA_TTABLE metatable, like for strings
- From: Philippe Verdy <verdy_p@...>
- Date: Sun, 17 Mar 2019 22:48:15 +0100
Why was the simple syntax addition for table constructors not augmented to use a ":" operator between table constructors, where "table1:table2" means attaching table2 as a metatable of table1? (I suggested using ":" for that purpose, but you may design another notation if you think it conflicts with other syntax, e.g. using "~" or ":=" or simply "=").
We should not even need to call setmetatable() with simple constructors.
Then what we do in LuaC is another problem. But probably a Lua state may also have an API to set a default metatable (defined as some "global" in the Lua state context), even if we can override this context by using "table1:null" with the same notation in Lua to explicitly remove this default.
Proposal:
While table metatable is not set, make it "t->metatable =
G(L)->mt[LUA_TTABLE]" by default, instead of "t->metatable =
NULL".
Access from Lua could be provided by special string e.g.
getmetatable("table")
And creation of this default metatable in tablelib init, like
for strings, additionally __index could also be set to
tablelib.
@ltable.c, line 421:
Table *luaH_new (lua_State *L) {
GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table));
Table *t = gco2t(o);
- t->metatable = NULL;
+ t->metatable = G(L)->mt[LUA_TTABLE];
t->flags = cast_byte(~0);
t->array = NULL;
t->sizearray = 0;
setnodevector(L, t, 0);
return t;
}
@lapi.c,, line 697:
LUA_API int lua_getmetatable (lua_State *L, int objindex) {
const TValue *obj;
Table *mt;
int res = 0;
lua_lock(L);
obj = index2addr(L, objindex);
switch (ttnov(obj)) {
case LUA_TTABLE:
mt = hvalue(obj)->metatable;
break;
case LUA_TUSERDATA:
mt = uvalue(obj)->metatable;
break;
+ case LUA_TSTRING: {
+ if (0 == strcmp(lua_tostring(L, objindex), "table"))
+ mt = G(L)->mt[LUA_TTABLE];
+ else
+ mt = G(L)->mt[LUA_TSTRING];
+ break;
+ }
default:
mt = G(L)->mt[ttnov(obj)];
break;
}
if (mt != NULL) {
sethvalue(L, L->top, mt);
api_incr_top(L);
res = 1;
}
lua_unlock(L);
return res;
}
@lapi.c, line 846:
LUA_API int lua_setmetatable (lua_State *L, int objindex) {
TValue *obj;
Table *mt;
lua_lock(L);
api_checknelems(L, 1);
obj = index2addr(L, objindex);
if (ttisnil(L->top - 1))
mt = NULL;
else {
api_check(L, ttistable(L->top - 1), "table expected");
mt = hvalue(L->top - 1);
}
switch (ttnov(obj)) {
case LUA_TTABLE: {
hvalue(obj)->metatable = mt;
if (mt) {
luaC_objbarrier(L, gcvalue(obj), mt);
luaC_checkfinalizer(L, gcvalue(obj), mt);
}
break;
}
case LUA_TUSERDATA: {
uvalue(obj)->metatable = mt;
if (mt) {
luaC_objbarrier(L, uvalue(obj), mt);
luaC_checkfinalizer(L, gcvalue(obj), mt);
}
break;
}
+ case LUA_TSTRING: {
+ if (0 == strcmp(lua_tostring(L, objindex), "table"))
+ G(L)->mt[LUA_TTABLE] = mt;
+ else
+ G(L)->mt[LUA_TSTRING] = mt;
+ break;
+ }
default: {
G(L)->mt[ttnov(obj)] = mt;
break;
}
}
L->top--;
lua_unlock(L);
return 1;
}
@ltablib.c, line 440:
+static void createmetatable (lua_State *L) {
+ lua_createtable(L, 0, 1); /* table to be metatable for
tables */
+ lua_pushliteral(L, "table"); /* 'table' string */
+ lua_pushvalue(L, -2); /* copy table */
+ lua_setmetatable(L, -2); /* set table as metatable for
tables */
+ lua_pop(L, 1); /* pop 'table' string */
+ lua_pushvalue(L, -2); /* get table library */
+ lua_setfield(L, -2, "__index"); /* metatable.__index =
table */
+ lua_pop(L, 1); /* pop metatable */
+}
LUAMOD_API int luaopen_table (lua_State *L) {
luaL_newlib(L, tab_funcs);
+ createmetatable(L);
#if defined(LUA_COMPAT_UNPACK)
/* _G.unpack = table.unpack */
lua_getfield(L, -1, "unpack");
lua_setglobal(L, "unpack");
#endif
return 1;
}
regards,
Pavel