lua-users home
lua-l archive

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


On 2017-01-26 22:49, Egor Skriptunoff wrote:
> On Thu, Jan 26, 2017 at 5:50 AM, Charles Heywood wrote:
>> Is there a rawtype() planned to act as previous versions of type() 
>> would?
> Instead of introducing new function "rawtype()", good old "type()" 
> may return two values: raw type and "specialized" type:
> 
> local t = setmetatable({}, {__name = "MyType"}) print(type({}))  -->
>  "table" print(type(t))  --> "table", "MyType"
> 
> BTW, this way "math.type()" could be removed as it does not needed 
> anymore:
> 
> print(type(42))  -->  "number", "integer" print(type(3.14))  --> 
> "number", "float"

I like the idea, but it's possible that this causes a significant
slow-down for type-based branching.  So let's do some measurements:

A quick & dirty test implementation (probably not optimal! and
incomplete):  It just gets __name if available, doesn't call functions
like math.type and so on.  (I wonder how that should work with e.g.
lpeg.type and other user additions.  Yet another metamethod: __type? m))

*** lbaselib.c-orig	2017-01-27 00:33:07.854011135 +0100
--- lbaselib.c-type2	2017-01-27 00:32:46.670792561 +0100
*************** static int luaB_type (lua_State *L) {
*** 202,207 ****
--- 202,212 ----
    int t = lua_type(L, 1);
    luaL_argcheck(L, t != LUA_TNONE, 1, "value expected");
    lua_pushstring(L, lua_typename(L, t));
+   int tt = luaL_getmetafield(L, 1, "__name");
+   if (tt == LUA_TSTRING)
+     return 2;
+   if (tt != LUA_TNIL)
+     lua_settop(L, -2);
    return 1;
  }

And a test script (doesn't do much besides calling type() in a loop):

-----
function typecase( v )
	local t = type( v )
	if t == "number" then  return "n"  end
	if t == "string" then  return "s"  end
	if t == "table" then  return "t"  end
	if t == "nil" then  return "x"  end
	return "?"
end
vals = { "foo", 23, true, io.stdin, nil, {}, setmetatable( {}, { __name
= false } ) }
local N = 2000000
for i = 1, 5 do
	t0 = os.clock()
	for i = 1, N do  typecase( vals[math.random( 7 )] )  end
	t1 = os.clock()
	print( arg[-2], N, t1-t0 )
end
-----

Result:

./lua_orig	2000000	1.005907
./lua_orig	2000000	0.999243
./lua_orig	2000000	0.997433
./lua_orig	2000000	0.997195
./lua_orig	2000000	0.997136
./lua_type2	2000000	1.119795
./lua_type2	2000000	1.119341
./lua_type2	2000000	1.119024
./lua_type2	2000000	1.119046
./lua_type2	2000000	1.119908

So roughly 10% overhead for something that usually isn't used.  Not too
bad, but not that nice either.  (A more efficient version may be better
- if anyone wants to try.  A more feature-complete version might also be
interesting.)

I like the general direction of the idea (there are more concepts of
"type" than just that of the seven primitive types), but it's not
something to quickly add, rather think some more about it first.

-- nobody