lua-users home
lua-l archive

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

Josh Haberman wrote:
> Speaking as someone who has previously asked for a __hasheq
> metamethod [0], I got over it, and I would hate for this slippery
> slope worry to lead to semantics where:
>   1 == 1LL
>   t[1] != t[1LL]
> That sounds extremely counter-intuitive.

Then you'll be even more surprised that t[1LL] != t[1LL], because
neither cdata not cdata literals are interned. 64 bit integers are
(REALLY!) unsuitable as table keys. One wouldn't come up with code
like this by accident, so one simply shouldn't write such code.

Suppose for a moment one would go with value hash semantics:

Then t[1LL] should map to t[1], so both would need to end up in
the array part of a table. Ok, so a table traversal would return
the key as 1 and not 1LL, which may lead to even more confusion.

And then t[10000000000000000LL] needs to map to t[1e16]. But
t[9999999999999999LL] shouldn't map to t[1e16], even though
tonumber(9999999999999999LL) == 1e16. And the final catch is that
t[-1LL] and t[-1ULL] better both map to t[-1], even though
tonumber(-1LL) == -1 and tonumber(-1ULL) == ~1.844674407371e+19.

Ouch! That's a can of worms I *really* don't want to open. This is
not ever going to work in a sensible way.

So use tonumber() or tostring() for 64 bit integer keys, depending
on which semantics you find more agreeable.

The alternative is to explicitly disallow cdata as table keys. But
this is quite useful for aggregate cdata (arrays, structs),
because their addresses are unique. And checking for scalar cdata
is kind of expensive in that code path, so I'd rather not do it.

I'll stay with the principle that Lua gives you the mechanism, but
it's your own business to shoot yourself in the foot. IOW: "The
ultimate goal of API design is to equally displease everyone".

> I think a convincing
> response to anyone who asks to push this further is that table
> indexing follows the same rules as "==", and you've already
> concluded that "==" needs to work with 64-bit integers.

Umm, but table indexing already doesn't follow the same rules as
"==", because it doesn't respect __eq metamethods:

  local mt = { __eq = function(a, b) return a[1] == b[1] end }
  local ka = setmetatable({1}, mt)
  local kb = setmetatable({1}, mt)

  print(ka == kb) --> true
  local t = {}; t[ka] = "test"; print(t[kb]) --> nil

And there's no cheap or simple way to make it do that. Basically
you'd need to intern all keys (or delegate to string interning)
or completely change the way Lua hash tables work.