— If two distinct userdata’s return the same type+value for __key Lua will think they are the same value and bad things will happen if they are put in the same table, possibly crashing Lua. Not good.
This won't crash Lua.
A hypothetical design that is not yet implemented but you know it won’t have any problems. Hmmm. Let’s think a moment. I store normal table item t[10] = “ten”. Then someone stores t[u] = “uten” where u is a userdata whose __key metamethod returns 10. What happens? If the original store was into the array part, Lua can’t continue to use this because it has to allocate a cell to store the userdata pointer. In fact, it needs to evict the key+value from the array part and move to to the hash part, and then allocate THREE cells: one for the return value of __key, one for the userdata and one for the string value. And what about this code...?
It replaces t[10], obviously. Just like t[10.0] replaces t[10]. t[u] = nil
If __key() for u returns something other than 10, really surprising things are going to happen.
Like what?
Like it deleting another totally unrelated key+value pair from the table, and if you don’t find that surprising then I don’t know what to say. As has been pointed out here many times, if a proposed feature is going to have a performance impact on the majority of users, it had better also have a benefit for the majority of users. Adding __key will certainly impact everyone (added logic in main code paths of the table module, extra cells to store user-returned keys etc). Will the majority also benefit? I don’t see that.
Added logic in the table module? Extra cells? What? We don't have extra cells for floats and we don't have added logic to handle floats, yet floats decay into integers if they have integral value, so why would __key need them?
ok, I’ll explain this again. Ignoring for a moment the array part of a table, each table entry contains two items: a key and value. Both these are stored in “cells”, the Lua version of a typed value. Let’s focus on the key, since we are discussing this. For a value of 100.0, Lua first notices it’s an integral float, coerces that float value to 100 (an integer), and stores this value in the cell. So the key is a cell with a type of integer and a value of 100 (I’m simplifying a bit here). But when you add the __key metamethod, things are very different. First, Lua has to store the userdata reference (as otherwise it would be unreferenced and subject to garbage collection). However, you ALSO have to save the “key” (from __key) .. which is another type+value cell. So in this case the key part of the key+value entry in the table has TWO cells, not one: one for the userdata and one for whatever it is being indexed by; the return value of __key. So you have new code paths and extra data for each key+value entry in a table.
The alternative of course is Lua calls __key every single time it needs to compare the key for a given table entry. Good luck with performance, And good luck if __key returns inconsistent values. And as others have noted, a better solution to the real problem of the OP is interning the bigint values so that two bigints are always the same userdata, which renders __key unnecessary.
And removes interoperability with plain Lua values. The point isn't to just access the same value from 2 different objects - this isn't some sort of __hash mechanism. The point is to interoperate with plain Lua values.
Which can be handled with metamethods on the userdata, such as __eq etc.
—Tim
|