[LUA]: Cannot use userdata as table index

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

[LUA]: Cannot use userdata as table index

Борис Александров
Example code:

" temp = {}
  temp['string'] = 'foobar'
  temp[GetPlayer(0)] = 'player'
  temp[GetEntity(0)] = 'entity'

  print(temp['string']) -- foobar
  print(temp[GetPlayer(0)]) -- nil
  print(temp[GetEntity(0)])  -- nil

  for k,v in pairs(temp) do
     print(k,v)  ----- stringfoobar
                   ------ Player(0)player
                   ------ Entity(0)entity
  end
"
   
Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Rob Kendrick-2
On Sat, Jul 11, 2015 at 01:41:44AM +1000, Борис Александров wrote:

> Example code:
>
> " temp = {}
>   temp['string'] = 'foobar'
>   temp[GetPlayer(0)] = 'player'
>   temp[GetEntity(0)] = 'entity'
>
>   print(temp['string']) -- foobar
>   print(temp[GetPlayer(0)]) -- nil
>   print(temp[GetEntity(0)])  -- nil


What does the following display?
        print(GetPlayer(0), GetPlayer(0))

B.

Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Борис Александров
Player(0)Player(0)

2015-07-11 1:44 GMT+10:00 Rob Kendrick <[hidden email]>:
On Sat, Jul 11, 2015 at 01:41:44AM +1000, Борис Александров wrote:
> Example code:
>
> " temp = {}
>   temp['string'] = 'foobar'
>   temp[GetPlayer(0)] = 'player'
>   temp[GetEntity(0)] = 'entity'
>
>   print(temp['string']) -- foobar
>   print(temp[GetPlayer(0)]) -- nil
>   print(temp[GetEntity(0)])  -- nil


What does the following display?
        print(GetPlayer(0), GetPlayer(0))

B.


Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Choonster TheMage
On 11 July 2015 at 01:59, Борис Александров <[hidden email]> wrote:

> Player(0)Player(0)
>
> 2015-07-11 1:44 GMT+10:00 Rob Kendrick <[hidden email]>:
>>
>> On Sat, Jul 11, 2015 at 01:41:44AM +1000, Борис Александров wrote:
>> > Example code:
>> >
>> > " temp = {}
>> >   temp['string'] = 'foobar'
>> >   temp[GetPlayer(0)] = 'player'
>> >   temp[GetEntity(0)] = 'entity'
>> >
>> >   print(temp['string']) -- foobar
>> >   print(temp[GetPlayer(0)]) -- nil
>> >   print(temp[GetEntity(0)])  -- nil
>>
>>
>> What does the following display?
>>         print(GetPlayer(0), GetPlayer(0))
>>
>> B.
>>
>

Can you remove the __eq and __tostring metamethods from the userdata
and run this code?

print("Equal?", GetPlayer(0) == GetPlayer(0))
print("Addresses", GetPlayer(0), GetPlayer(0))

If GetPlayer always returns the same userdata for a given player ID,
the first line should be "Equal? true" and the second should have the
same hexadecimal digit twice.

If GetPlayer returns a different userdata each time, you won't be able
to use it as a table key reliably (since the userdata objects won't be
raw equal to each other).

Regards,
Choonster

Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Choonster TheMage
On 11 July 2015 at 02:08, Choonster TheMage <[hidden email]> wrote:

> On 11 July 2015 at 01:59, Борис Александров <[hidden email]> wrote:
>> Player(0)Player(0)
>>
>> 2015-07-11 1:44 GMT+10:00 Rob Kendrick <[hidden email]>:
>>>
>>> On Sat, Jul 11, 2015 at 01:41:44AM +1000, Борис Александров wrote:
>>> > Example code:
>>> >
>>> > " temp = {}
>>> >   temp['string'] = 'foobar'
>>> >   temp[GetPlayer(0)] = 'player'
>>> >   temp[GetEntity(0)] = 'entity'
>>> >
>>> >   print(temp['string']) -- foobar
>>> >   print(temp[GetPlayer(0)]) -- nil
>>> >   print(temp[GetEntity(0)])  -- nil
>>>
>>>
>>> What does the following display?
>>>         print(GetPlayer(0), GetPlayer(0))
>>>
>>> B.
>>>
>>
>
> Can you remove the __eq and __tostring metamethods from the userdata
> and run this code?
>
> print("Equal?", GetPlayer(0) == GetPlayer(0))
> print("Addresses", GetPlayer(0), GetPlayer(0))
>
> If GetPlayer always returns the same userdata for a given player ID,
> the first line should be "Equal? true" and the second should have the
> same hexadecimal digit twice.
>
> If GetPlayer returns a different userdata each time, you won't be able
> to use it as a table key reliably (since the userdata objects won't be
> raw equal to each other).
>
> Regards,
> Choonster

You could also just use rawequal to check if they're equal (I forgot
about it before):

print("Equal?", rawequal(GetPlayer(0), GetPlayer(0)))

Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Борис Александров
why addresses of two userdata's should be equal? they are dynamically allocated using ( lua_newuserdata ).
Also rawequal works until i'm commented __tostring and __equal metamethods

2015-07-11 2:10 GMT+10:00 Choonster TheMage <[hidden email]>:
On 11 July 2015 at 02:08, Choonster TheMage <[hidden email]> wrote:
> On 11 July 2015 at 01:59, Борис Александров <[hidden email]> wrote:
>> Player(0)Player(0)
>>
>> 2015-07-11 1:44 GMT+10:00 Rob Kendrick <[hidden email]>:
>>>
>>> On Sat, Jul 11, 2015 at 01:41:44AM +1000, Борис Александров wrote:
>>> > Example code:
>>> >
>>> > " temp = {}
>>> >   temp['string'] = 'foobar'
>>> >   temp[GetPlayer(0)] = 'player'
>>> >   temp[GetEntity(0)] = 'entity'
>>> >
>>> >   print(temp['string']) -- foobar
>>> >   print(temp[GetPlayer(0)]) -- nil
>>> >   print(temp[GetEntity(0)])  -- nil
>>>
>>>
>>> What does the following display?
>>>         print(GetPlayer(0), GetPlayer(0))
>>>
>>> B.
>>>
>>
>
> Can you remove the __eq and __tostring metamethods from the userdata
> and run this code?
>
> print("Equal?", GetPlayer(0) == GetPlayer(0))
> print("Addresses", GetPlayer(0), GetPlayer(0))
>
> If GetPlayer always returns the same userdata for a given player ID,
> the first line should be "Equal? true" and the second should have the
> same hexadecimal digit twice.
>
> If GetPlayer returns a different userdata each time, you won't be able
> to use it as a table key reliably (since the userdata objects won't be
> raw equal to each other).
>
> Regards,
> Choonster

You could also just use rawequal to check if they're equal (I forgot
about it before):

print("Equal?", rawequal(GetPlayer(0), GetPlayer(0)))


Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Борис Александров
http://prntscr.com/7r4ecw  It seems to me that lua compares table index and given value by address, not by _equal metamethod 

2015-07-11 2:18 GMT+10:00 Борис Александров <[hidden email]>:
why addresses of two userdata's should be equal? they are dynamically allocated using ( lua_newuserdata ).
Also rawequal works until i'm commented __tostring and __equal metamethods

2015-07-11 2:10 GMT+10:00 Choonster TheMage <[hidden email]>:
On 11 July 2015 at 02:08, Choonster TheMage <[hidden email]> wrote:
> On 11 July 2015 at 01:59, Борис Александров <[hidden email]> wrote:
>> Player(0)Player(0)
>>
>> 2015-07-11 1:44 GMT+10:00 Rob Kendrick <[hidden email]>:
>>>
>>> On Sat, Jul 11, 2015 at 01:41:44AM +1000, Борис Александров wrote:
>>> > Example code:
>>> >
>>> > " temp = {}
>>> >   temp['string'] = 'foobar'
>>> >   temp[GetPlayer(0)] = 'player'
>>> >   temp[GetEntity(0)] = 'entity'
>>> >
>>> >   print(temp['string']) -- foobar
>>> >   print(temp[GetPlayer(0)]) -- nil
>>> >   print(temp[GetEntity(0)])  -- nil
>>>
>>>
>>> What does the following display?
>>>         print(GetPlayer(0), GetPlayer(0))
>>>
>>> B.
>>>
>>
>
> Can you remove the __eq and __tostring metamethods from the userdata
> and run this code?
>
> print("Equal?", GetPlayer(0) == GetPlayer(0))
> print("Addresses", GetPlayer(0), GetPlayer(0))
>
> If GetPlayer always returns the same userdata for a given player ID,
> the first line should be "Equal? true" and the second should have the
> same hexadecimal digit twice.
>
> If GetPlayer returns a different userdata each time, you won't be able
> to use it as a table key reliably (since the userdata objects won't be
> raw equal to each other).
>
> Regards,
> Choonster

You could also just use rawequal to check if they're equal (I forgot
about it before):

print("Equal?", rawequal(GetPlayer(0), GetPlayer(0)))



Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Choonster TheMage
On 11 July 2015 at 02:23, Борис Александров <[hidden email]> wrote:
> http://prntscr.com/7r4ecw  It seems to me that lua compares table index and
> given value by address, not by _equal metamethod
>

Yes, this is explained in the manual:

The indexing of tables follows the definition of raw equality in the
language. The expressions a[i] and a[j] denote the same table element
if and only if iand j are raw equal (that is, equal without
metamethods).

http://www.lua.org/manual/5.3/manual.html#2.1

Every time you call lua_newuserdata, you're creating a new object
that's not raw equal to any other object.

Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Brigham Toskin
On Fri, Jul 10, 2015 at 9:28 AM, Choonster TheMage <[hidden email]> wrote:
On 11 July 2015 at 02:23, Борис Александров <[hidden email]> wrote:
> http://prntscr.com/7r4ecw  It seems to me that lua compares table index and
> given value by address, not by _equal metamethod
>

Yes, this is explained in the manual:

The indexing of tables follows the definition of raw equality in the
language. The expressions a[i] and a[j] denote the same table element
if and only if iand j are raw equal (that is, equal without
metamethods).

http://www.lua.org/manual/5.3/manual.html#2.1

Every time you call lua_newuserdata, you're creating a new object
that's not raw equal to any other object.


Doing something like the following would demonstrate you can use userdata for table keys; it just seems like you're not using them the way you thought you were.

    for k,v in pairs(temp) do print(k,v) end

--
Brigham Toskin
Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Tom N Harris-2
In reply to this post by Борис Александров
On Saturday, July 11, 2015 02:23:14 AM Борис Александров wrote:
> http://prntscr.com/7r4ecw  It seems to me that lua compares table index and
> given value by address, not by _equal metamethod
>

This is correct. Only the primitive

Since the GetPlayer objects define a __tostring metamethod, you can convert the
userdata to string for use as a table key.

The __equals metamethod wouldn't be useful for tables. Lua would need a __hash
metamethod that returns a value suitable as a table key. But I wonder what
strange things could happen if A==B is not the same as hash(A)==hash(B)?

And anyway you can roll your own table with meta-keys.

function objecthash(o)
    -- exercise for the reader: memoize keys for the lifetime of the object
    local mt = getmetatable(o)
    if mt and mt.__hash then
        return mt.__hash(o)
    end
    return o
end
__index = function(t,o)
    return getmetatable(t).__proxy[objecthash(o)]
end
__newindex = function(t,o,v)
    getmetatable(t).__proxy[objecthash(o)] = v
end

--
tom <[hidden email]>

Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Coda Highland
On Fri, Jul 10, 2015 at 9:45 AM, Tom N Harris <[hidden email]> wrote:

> On Saturday, July 11, 2015 02:23:14 AM Борис Александров wrote:
>> http://prntscr.com/7r4ecw  It seems to me that lua compares table index and
>> given value by address, not by _equal metamethod
>>
>
> This is correct. Only the primitive
>
> Since the GetPlayer objects define a __tostring metamethod, you can convert the
> userdata to string for use as a table key.
>
> The __equals metamethod wouldn't be useful for tables. Lua would need a __hash
> metamethod that returns a value suitable as a table key. But I wonder what
> strange things could happen if A==B is not the same as hash(A)==hash(B)?
>

This is called a hash collision, and ANY hashtable implementation
(including the one already in Lua) has to deal with it. Essentially
what it means is that the entries of the hashtable are themselves
key-value lists, and you then do an equality check on the keys to find
out which of those values is the one you're actually looking for. The
idea is that the probability of a collision is low enough that you
won't need to check very many keys.

/s/ Adam

Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Rena
In reply to this post by Борис Александров

On Jul 10, 2015 12:19 PM, "Борис Александров" <[hidden email]> wrote:
>
> why addresses of two userdata's should be equal? they are dynamically allocated using ( lua_newuserdata ).
> Also rawequal works until i'm commented __tostring and __equal metamethods
>
> 2015-07-11 2:10 GMT+10:00 Choonster TheMage <[hidden email]>:
>>
>> On 11 July 2015 at 02:08, Choonster TheMage <[hidden email]> wrote:
>> > On 11 July 2015 at 01:59, Борис Александров <[hidden email]> wrote:
>> >> Player(0)Player(0)
>> >>
>> >> 2015-07-11 1:44 GMT+10:00 Rob Kendrick <[hidden email]>:
>> >>>
>> >>> On Sat, Jul 11, 2015 at 01:41:44AM +1000, Борис Александров wrote:
>> >>> > Example code:
>> >>> >
>> >>> > " temp = {}
>> >>> >   temp['string'] = 'foobar'
>> >>> >   temp[GetPlayer(0)] = 'player'
>> >>> >   temp[GetEntity(0)] = 'entity'
>> >>> >
>> >>> >   print(temp['string']) -- foobar
>> >>> >   print(temp[GetPlayer(0)]) -- nil
>> >>> >   print(temp[GetEntity(0)])  -- nil
>> >>>
>> >>>
>> >>> What does the following display?
>> >>>         print(GetPlayer(0), GetPlayer(0))
>> >>>
>> >>> B.
>> >>>
>> >>
>> >
>> > Can you remove the __eq and __tostring metamethods from the userdata
>> > and run this code?
>> >
>> > print("Equal?", GetPlayer(0) == GetPlayer(0))
>> > print("Addresses", GetPlayer(0), GetPlayer(0))
>> >
>> > If GetPlayer always returns the same userdata for a given player ID,
>> > the first line should be "Equal? true" and the second should have the
>> > same hexadecimal digit twice.
>> >
>> > If GetPlayer returns a different userdata each time, you won't be able
>> > to use it as a table key reliably (since the userdata objects won't be
>> > raw equal to each other).
>> >
>> > Regards,
>> > Choonster
>>
>> You could also just use rawequal to check if they're equal (I forgot
>> about it before):
>>
>> print("Equal?", rawequal(GetPlayer(0), GetPlayer(0)))
>>
>

We don't know the implementation of GetPlayer(). Guessing from its name I would expect it to return the same object every time given the same input. If that's not the case then no, you won't be able to use it as a table key, since you get back a different key each time.

--
Sent from my Game Boy.

Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Brigham Toskin
On Fri, Jul 10, 2015 at 10:24 AM, Rena <[hidden email]> wrote:

On Jul 10, 2015 12:19 PM, "Борис Александров" <[hidden email]> wrote:
>
> why addresses of two userdata's should be equal? they are dynamically allocated using ( lua_newuserdata ).
> Also rawequal works until i'm commented __tostring and __equal metamethods
>
> 2015-07-11 2:10 GMT+10:00 Choonster TheMage <[hidden email]>:
>>
>> On 11 July 2015 at 02:08, Choonster TheMage <[hidden email]> wrote:
>> > On 11 July 2015 at 01:59, Борис Александров <[hidden email]> wrote:
>> >> Player(0)Player(0)
>> >>
>> >> 2015-07-11 1:44 GMT+10:00 Rob Kendrick <[hidden email]>:
>> >>>
>> >>> On Sat, Jul 11, 2015 at 01:41:44AM +1000, Борис Александров wrote:
>> >>> > Example code:
>> >>> >
>> >>> > " temp = {}
>> >>> >   temp['string'] = 'foobar'
>> >>> >   temp[GetPlayer(0)] = 'player'
>> >>> >   temp[GetEntity(0)] = 'entity'
>> >>> >
>> >>> >   print(temp['string']) -- foobar
>> >>> >   print(temp[GetPlayer(0)]) -- nil
>> >>> >   print(temp[GetEntity(0)])  -- nil
>> >>>
>> >>>
>> >>> What does the following display?
>> >>>         print(GetPlayer(0), GetPlayer(0))
>> >>>
>> >>> B.
>> >>>
>> >>
>> >
>> > Can you remove the __eq and __tostring metamethods from the userdata
>> > and run this code?
>> >
>> > print("Equal?", GetPlayer(0) == GetPlayer(0))
>> > print("Addresses", GetPlayer(0), GetPlayer(0))
>> >
>> > If GetPlayer always returns the same userdata for a given player ID,
>> > the first line should be "Equal? true" and the second should have the
>> > same hexadecimal digit twice.
>> >
>> > If GetPlayer returns a different userdata each time, you won't be able
>> > to use it as a table key reliably (since the userdata objects won't be
>> > raw equal to each other).
>> >
>> > Regards,
>> > Choonster
>>
>> You could also just use rawequal to check if they're equal (I forgot
>> about it before):
>>
>> print("Equal?", rawequal(GetPlayer(0), GetPlayer(0)))
>>
>

We don't know the implementation of GetPlayer(). Guessing from its name I would expect it to return the same object every time given the same input. If that's not the case then no, you won't be able to use it as a table key, since you get back a different key each time.

--
Sent from my Game Boy.


A reasonable alternative might be to use a string like "player0" as the key, if it's not too expensive to generate such a string.

--
Brigham Toskin
Reply | Threaded
Open this post in threaded view
|

Re: [LUA]: Cannot use userdata as table index

Brigham Toskin
On Fri, Jul 10, 2015 at 11:57 AM, Brigham Toskin <[hidden email]> wrote:
On Fri, Jul 10, 2015 at 10:24 AM, Rena <[hidden email]> wrote:

On Jul 10, 2015 12:19 PM, "Борис Александров" <[hidden email]> wrote:
>
> why addresses of two userdata's should be equal? they are dynamically allocated using ( lua_newuserdata ).
> Also rawequal works until i'm commented __tostring and __equal metamethods
>
> 2015-07-11 2:10 GMT+10:00 Choonster TheMage <[hidden email]>:
>>
>> On 11 July 2015 at 02:08, Choonster TheMage <[hidden email]> wrote:
>> > On 11 July 2015 at 01:59, Борис Александров <[hidden email]> wrote:
>> >> Player(0)Player(0)
>> >>
>> >> 2015-07-11 1:44 GMT+10:00 Rob Kendrick <[hidden email]>:
>> >>>
>> >>> On Sat, Jul 11, 2015 at 01:41:44AM +1000, Борис Александров wrote:
>> >>> > Example code:
>> >>> >
>> >>> > " temp = {}
>> >>> >   temp['string'] = 'foobar'
>> >>> >   temp[GetPlayer(0)] = 'player'
>> >>> >   temp[GetEntity(0)] = 'entity'
>> >>> >
>> >>> >   print(temp['string']) -- foobar
>> >>> >   print(temp[GetPlayer(0)]) -- nil
>> >>> >   print(temp[GetEntity(0)])  -- nil
>> >>>
>> >>>
>> >>> What does the following display?
>> >>>         print(GetPlayer(0), GetPlayer(0))
>> >>>
>> >>> B.
>> >>>
>> >>
>> >
>> > Can you remove the __eq and __tostring metamethods from the userdata
>> > and run this code?
>> >
>> > print("Equal?", GetPlayer(0) == GetPlayer(0))
>> > print("Addresses", GetPlayer(0), GetPlayer(0))
>> >
>> > If GetPlayer always returns the same userdata for a given player ID,
>> > the first line should be "Equal? true" and the second should have the
>> > same hexadecimal digit twice.
>> >
>> > If GetPlayer returns a different userdata each time, you won't be able
>> > to use it as a table key reliably (since the userdata objects won't be
>> > raw equal to each other).
>> >
>> > Regards,
>> > Choonster
>>
>> You could also just use rawequal to check if they're equal (I forgot
>> about it before):
>>
>> print("Equal?", rawequal(GetPlayer(0), GetPlayer(0)))
>>
>

We don't know the implementation of GetPlayer(). Guessing from its name I would expect it to return the same object every time given the same input. If that's not the case then no, you won't be able to use it as a table key, since you get back a different key each time.

--
Sent from my Game Boy.


A reasonable alternative might be to use a string like "player0" as the key, if it's not too expensive to generate such a string.

--
Brigham Toskin

Quick addendum to my last message:

If you know you want player 0 specifically, you can just use the literal string "player0", which is cheap in Lua.

If you need to choose the player by ID parametrically, you could do something like temp[players[id]], where players is something like:

    players = { [0] = "player0", "player1", "player2", ... }

It's a double table lookup, which adds some overhead, but one of them is probably an array lookup (except for 0), and I'd imagine it's still faster than trying to use...

    "player" + id

...all over the place.

--
Brigham Toskin