lua-users home
lua-l archive

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


The ability to attach a metatable to a userdata value is, I feel, a great feature of Lua as it allows C code to integrate new types into the language cleanly and efficiently. With a correctly setup metatable, a userdata item can behave as a first-class citizen in Lua code.

However, it seems to me that there is one hole in this clean model: the inability of a metatable to project a "type" into the Lua code space. Specifically, regardless of metatable, the value of type(someuserdata) is always "userdata". This means if I have several different userdata "types" in Lua code I cannot use them polymorphically without tracking their type manually (using, say, an ephemeron table). While tostring() can be used as a workaround (as it is for example with file handles) this seems too much like a hack to me; tostring() is supposed to return a value, not a type.

To my mind, the most correct way for this to work would be for the type() function to return the user-defined type by returning the value of __metatable (like getmetatable()). However, this would of course break existing code, so i feel we need a new function, usertype() that behave like type() except when there is a __metatable field in the metatable, in which case it returns this instead. For example:

function usertype(v)
local mt = getmetatable(v)
if mt ~= "table" return mt else return type(v)
end

An alternative would be to create a new metatable entry, such as __type, that if present is used as the "type" of the userdata/table in much the same way __tostring() is used by the tostring() function.

This allows a userdata metatable to return a string from usertype() in a way that extends the type() namespace. Of course this has the potential disadvantage that adding new types to Lua is harder, as the private namespace of the type() function is now opened up to add-in types, but this can be handled by (for example) decorating the user-defined types in usertype() in some manner. For example:

function usertype(v)
local ty = getmetatable(v).__type
return ty and "_" .. ty or type(v)
end

Of course, it's not necessary to add this to the language; after all I just wrote the code in the above example. However, I feel that this is a generic feature that needs to always be available for people who are writing addon libraries or packages for Lua.

Thoughts anyone?
--Tim