There are some very confusing behaviors in Lua C API. Here are some explanations for these. (Tested on Lua 5.4)
1. Type of number, integer, string
Operations like lua_isnumber
, lua_pushinteger
, lua_isstring
don’t mean checking the value’s type:
- Values with type
number
can also get true oflua_isstring
. (Number is also string) - There are no integer types in Lua. Values generated by
lua_pushinteger
have typenumber
. - Only values generated by
lua_pushinteger
can get true oflua_isinteger
. (But get false afterlua_tostring
) lua_isnumber
gets true if the value is a realnumber
or astring
but convertible to number.
lua_tostring
will implicitly convert number to string:
- After calling
lua_tostring
on a value of typenumber
, the value’s type will change tostring
implicitly, but it is stilllua_isnumber
. - After calling
lua_tostring
on a value generated bylua_pushinteger
, it cannot get true oflua_isinteger
anymore. (String is always not integer)
Test cases
Lua value generated by | lua_type | lua_typename | lua_isinteger | lua_isnumber | lua_isstring |
---|---|---|---|---|---|
lua_pushinteger |
LUA_TNUMBER : 3 | number | true | true | true |
lua_pushinteger then lua_tostring |
LUA_TSTRING : 4 | string | false | true | true |
lua_pushnumber [1] |
LUA_TNUMBER : 3 | number | false | true | true |
lua_pushnumber [1] then lua_tostring |
LUA_TSTRING : 4 | string | false | true | true |
lua_pushstring on string of number[2] |
LUA_TSTRING : 4 | string | false | true | true |
lua_pushstring on string of not number[3] |
LUA_TSTRING : 4 | string | false | false | true |
[1] Applies to all float or integer numbers. e.g. lua_pushnumber(L, 0)
, lua_pushnumber(L, 123)
, lua_pushnumber(L, 0.1)
, etc.
[2] e.g. “123”, “1.23”, “12.”, “.12”, “-1.23”, “+1.23”, “1.2e3”, “-1.2E-3”, etc.
[3] e.g. “1.2.3”, “1+2”, “hello”, “inf”, etc.
Conclusion
- Integer is not a type. Integer is a special case of number.
- Number is also string.
- String is also number if it is convertible to number.
- String is always not integer.
lua_tostring
will implicitly convert number to string.
More to say
Not like lua_tostring
, luaL_tolstring
won’t convert number to string.
But it can convert any value to string, while lua_tostring
will return NULL
if the value is not a string or number.
2. Type of userdata, light userdata
Userdata and light userdata have different type ID, but they have a same type name.
lua_islightuserdata
is a subset of lua_isuserdata
:
lua_isuserdata
returns true for both userdata and light userdata. (Light userdata is userdata)lua_islightuserdata
only returns true for light userdata.
Test cases
Lua value generated by | lua_type | lua_typename | lua_islightuserdata | lua_isuserdata |
---|---|---|---|---|
lua_pushlightuserdata |
LUA_TLIGHTUSERDATA : 2 | userdata | true | true |
lua_newuserdata |
LUA_TUSERDATA : 7 | userdata | false | true |
Conclusion
- Type ID of light userdata is “LUA_TLIGHTUSERDATA” (value 2), type ID of userdata is “LUA_TUSERDATA” (value 7), but they have a same type name “userdata”.
- Light userdata is a subset of userdata, although they have different type ID.
- Light userdata is userdata.
3. Metatable of light userdata
Light userdata (unlike heavy userdata) have no per-value metatables. All light userdata share the same metatable, which by default is not set (nil).