Comparing userdata with other types

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

Comparing userdata with other types

Ivo Beltchev
Hi

I am embedding Lua in my application and I want to expose some objects
to the Lua scripts. Different objects have different sets of properties.
For example object1 can have speed and length and object2 can have mass
and friction.

Currently if the script wants to check if an object has mass>20 it has
to do:

if (obj.mass and obj.mass>20)...

because obj.mass may be nil and then comparing it to 20 fails. So for
properties that don't exist I want to create a special object (NIL) that
can be safely used in expressions:
NIL+x -> NIL
NIL..x -> NIL
NIL[x] -> NIL
#NIL -> 0
NIL==NIL -> true
NIL==nil -> true (not so sure about this)
NIL>20 -> false
...

You get the idea.

Then I can simply write:
if (obj.mass>20) ...

However the __lt metamethod is not being called when I compare NIL to a
number. It is used only if the two values are of the same type.
Otherwise Lua throws an error.

Any ideas how to do this? A NAN value almost does what I want but it
can't be indexed, and also NAN~=NAN.

Thanks
Ivo

Reply | Threaded
Open this post in threaded view
|

Re: Comparing userdata with other types

Duncan Cross
Unfortunately I don't think there is a way to get what you want
without a custom modification of Lua, in a way that could potentially
make comparisons slightly slower.

The only thing I'd mention is that you could use "or" to specify a
default - instead of the cumbersome 'if obj.mass and obj.mass > 20'
you could do 'if (obj.mass or 0) > 20'.

-Duncan

On Sun, May 31, 2009 at 7:41 PM, Ivo Beltchev <[hidden email]> wrote:

> Hi
>
> I am embedding Lua in my application and I want to expose some objects to
> the Lua scripts. Different objects have different sets of properties. For
> example object1 can have speed and length and object2 can have mass and
> friction.
>
> Currently if the script wants to check if an object has mass>20 it has to
> do:
>
> if (obj.mass and obj.mass>20)...
>
> because obj.mass may be nil and then comparing it to 20 fails. So for
> properties that don't exist I want to create a special object (NIL) that can
> be safely used in expressions:
> NIL+x -> NIL
> NIL..x -> NIL
> NIL[x] -> NIL
> #NIL -> 0
> NIL==NIL -> true
> NIL==nil -> true (not so sure about this)
> NIL>20 -> false
> ...
>
> You get the idea.
>
> Then I can simply write:
> if (obj.mass>20) ...
>
> However the __lt metamethod is not being called when I compare NIL to a
> number. It is used only if the two values are of the same type. Otherwise
> Lua throws an error.
>
> Any ideas how to do this? A NAN value almost does what I want but it can't
> be indexed, and also NAN~=NAN.
>
> Thanks
> Ivo
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Comparing userdata with other types

Ivo Beltchev
I had some luck with using a NAN value with a metatable for numbers. So now I have:
NIL+x -> NIL
NIL[x] -> NIL
NIL[x]=5 -> no error
#NIL -> 0
NIL>20 -> false

But I'm still having 2 problems:

1) NIL==NIL gives false. That's because the __eq metamethod is not being called for numbers at all, and normally NAN!=NAN. Is there a trick to get this to work? It is important because otherwise there is no convenient way to detect when the value is really NIL. Basically I want to do:
if (obj.mass==NIL) ...

2) Since I'm replacing the __index and __newindex for numbers, when I try to index a regular number I'm getting:
bad argument #1 to '?' (can't index a number value)

instead of the nicer standard message produced by the luaG_typeerror function:
attempt to index global 'a' (a number value)

Is there a way to use the luaG_typeerror myself? It requires a const TValue * argument and I don't know how to get it in my function.

Ivo


Duncan Cross wrote:
Unfortunately I don't think there is a way to get what you want
without a custom modification of Lua, in a way that could potentially
make comparisons slightly slower.

The only thing I'd mention is that you could use "or" to specify a
default - instead of the cumbersome 'if obj.mass and obj.mass > 20'
you could do 'if (obj.mass or 0) > 20'.

-Duncan

On Sun, May 31, 2009 at 7:41 PM, Ivo Beltchev [hidden email] wrote:
  
Hi

I am embedding Lua in my application and I want to expose some objects to
the Lua scripts. Different objects have different sets of properties. For
example object1 can have speed and length and object2 can have mass and
friction.

Currently if the script wants to check if an object has mass>20 it has to
do:

if (obj.mass and obj.mass>20)...

because obj.mass may be nil and then comparing it to 20 fails. So for
properties that don't exist I want to create a special object (NIL) that can
be safely used in expressions:
NIL+x -> NIL
NIL..x -> NIL
NIL[x] -> NIL
#NIL -> 0
NIL==NIL -> true
NIL==nil -> true (not so sure about this)
NIL>20 -> false
...

You get the idea.

Then I can simply write:
if (obj.mass>20) ...

However the __lt metamethod is not being called when I compare NIL to a
number. It is used only if the two values are of the same type. Otherwise
Lua throws an error.

Any ideas how to do this? A NAN value almost does what I want but it can't
be indexed, and also NAN~=NAN.

Thanks
Ivo


    

  
Reply | Threaded
Open this post in threaded view
|

Re: Comparing userdata with other types

Matthew Paul Del Buono
That's actually rather scary. You realise that all numbers share the same metatable, right? So not only are you impacting the comparison of your value NIL but also every other numerical comparison. This could lead to problems in the future, especially if the developer is unaware of this change. (I HAVE written, and still rely upon, code which relies upon the fact that NaN != NaN)

Matthew Del Buono

Sent from my Verizon Wireless BlackBerry


From: Ivo Beltchev
Date: Sun, 31 May 2009 15:05:19 -0700
To: Lua list<[hidden email]>
Subject: Re: Comparing userdata with other types

I had some luck with using a NAN value with a metatable for numbers. So now I have:
NIL+x -> NIL
NIL[x] -> NIL
NIL[x]=5 -> no error
#NIL -> 0
NIL>20 -> false

But I'm still having 2 problems:

1) NIL==NIL gives false. That's because the __eq metamethod is not being called for numbers at all, and normally NAN!=NAN. Is there a trick to get this to work? It is important because otherwise there is no convenient way to detect when the value is really NIL. Basically I want to do:
if (obj.mass==NIL) ...

2) Since I'm replacing the __index and __newindex for numbers, when I try to index a regular number I'm getting:
bad argument #1 to '?' (can't index a number value)

instead of the nicer standard message produced by the luaG_typeerror function:
attempt to index global 'a' (a number value)

Is there a way to use the luaG_typeerror myself? It requires a const TValue * argument and I don't know how to get it in my function.

Ivo


Duncan Cross wrote:
Unfortunately I don't think there is a way to get what you want without a custom modification of Lua, in a way that could potentially make comparisons slightly slower.  The only thing I'd mention is that you could use "or" to specify a default - instead of the cumbersome 'if obj.mass and obj.mass > 20' you could do 'if (obj.mass or 0) > 20'.  -Duncan  On Sun, May 31, 2009 at 7:41 PM, Ivo Beltchev [hidden email] wrote:   
Hi  I am embedding Lua in my application and I want to expose some objects to the Lua scripts. Different objects have different sets of properties. For example object1 can have speed and length and object2 can have mass and friction.  Currently if the script wants to check if an object has mass>20 it has to do:  if (obj.mass and obj.mass>20)...  because obj.mass may be nil and then comparing it to 20 fails. So for properties that don't exist I want to create a special object (NIL) that can be safely used in expressions: NIL+x -> NIL NIL..x -> NIL NIL[x] -> NIL #NIL -> 0 NIL==NIL -> true NIL==nil -> true (not so sure about this) NIL>20 -> false ...  You get the idea.  Then I can simply write: if (obj.mass>20) ...  However the __lt metamethod is not being called when I compare NIL to a number. It is used only if the two values are of the same type. Otherwise Lua throws an error.  Any ideas how to do this? A NAN value almost does what I want but it can't be indexed, and also NAN~=NAN.  Thanks Ivo       
   
Reply | Threaded
Open this post in threaded view
|

Re: Comparing userdata with other types

Patrick Donnelly
On Sun, May 31, 2009 at 5:29 PM,  <[hidden email]> wrote:
> That's actually rather scary. You realise that all numbers share the same
> metatable, right? So not only are you impacting the comparison of your value
> NIL but also every other numerical comparison. This could lead to problems
> in the future, especially if the developer is unaware of this change. (I
> HAVE written, and still rely upon, code which relies upon the fact that NaN
> != NaN)

You needn't worry. Numbers fall in the special case where the __eq
metamethod (among many others) is ignored.

--
-Patrick Donnelly

"Let all men know thee, but no man know thee thoroughly: Men freely
ford that see the shallows."

- Benjamin Franklin
Reply | Threaded
Open this post in threaded view
|

Re: Comparing userdata with other types

Ivo Beltchev
In reply to this post by Matthew Paul Del Buono
My metamethods only have a special behavior if the number is a very specific NAN value. There are billions of NANs, so the chance of this value occurring normally is negligible. And the special behavior is limited to __index, __newindex and __len, which should not be used in normal numeric operations anyway (aside from __eq, if I get it to work somehow).

[hidden email] wrote:
That's actually rather scary. You realise that all numbers share the same metatable, right? So not only are you impacting the comparison of your value NIL but also every other numerical comparison. This could lead to problems in the future, especially if the developer is unaware of this change. (I HAVE written, and still rely upon, code which relies upon the fact that NaN != NaN)

Matthew Del Buono

Sent from my Verizon Wireless BlackBerry


From: Ivo Beltchev
Date: Sun, 31 May 2009 15:05:19 -0700
To: Lua list[hidden email]
Subject: Re: Comparing userdata with other types
I had some luck with using a NAN value with a metatable for numbers. So now I have:
NIL+x -> NIL
NIL[x] -> NIL
NIL[x]=5 -> no error
#NIL -> 0
NIL>20 -> false

But I'm still having 2 problems:

1) NIL==NIL gives false. That's because the __eq metamethod is not being called for numbers at all, and normally NAN!=NAN. Is there a trick to get this to work? It is important because otherwise there is no convenient way to detect when the value is really NIL. Basically I want to do:
if (obj.mass==NIL) ...

2) Since I'm replacing the __index and __newindex for numbers, when I try to index a regular number I'm getting:
bad argument #1 to '?' (can't index a number value)

instead of the nicer standard message produced by the luaG_typeerror function:
attempt to index global 'a' (a number value)

Is there a way to use the luaG_typeerror myself? It requires a const TValue * argument and I don't know how to get it in my function.

Ivo


Duncan Cross wrote:
Unfortunately I don't think there is a way to get what you want without a custom modification of Lua, in a way that could potentially make comparisons slightly slower.  The only thing I'd mention is that you could use "or" to specify a default - instead of the cumbersome 'if obj.mass and obj.mass > 20' you could do 'if (obj.mass or 0) > 20'.  -Duncan  On Sun, May 31, 2009 at 7:41 PM, Ivo Beltchev [hidden email] wrote:   
Hi  I am embedding Lua in my application and I want to expose some objects to the Lua scripts. Different objects have different sets of properties. For example object1 can have speed and length and object2 can have mass and friction.  Currently if the script wants to check if an object has mass>20 it has to do:  if (obj.mass and obj.mass>20)...  because obj.mass may be nil and then comparing it to 20 fails. So for properties that don't exist I want to create a special object (NIL) that can be safely used in expressions: NIL+x -> NIL NIL..x -> NIL NIL[x] -> NIL #NIL -> 0 NIL==NIL -> true NIL==nil -> true (not so sure about this) NIL>20 -> false ...  You get the idea.  Then I can simply write: if (obj.mass>20) ...  However the __lt metamethod is not being called when I compare NIL to a number. It is used only if the two values are of the same type. Otherwise Lua throws an error.  Any ideas how to do this? A NAN value almost d
oes what I want but it can't be indexed, and also NAN~=NAN.  Thanks Ivo       
   
Reply | Threaded
Open this post in threaded view
|

Re: Comparing userdata with other types

Matthias Kluwe
In reply to this post by Ivo Beltchev
Hi!

2009/5/31 Ivo Beltchev <[hidden email]>:

> I am embedding Lua in my application and I want to expose some objects to
> the Lua scripts. Different objects have different sets of properties. For
> example object1 can have speed and length and object2 can have mass and
> friction.
>
> Currently if the script wants to check if an object has mass>20 it has to
> do:
>
> if (obj.mass and obj.mass>20)...

Personally, I like "cumbersome" code very much. To the reader, it
clearly tells what you want to do (check if the object has a property
"mass" and if it has, compare it).

Regards,
Matthias
Reply | Threaded
Open this post in threaded view
|

Re: Comparing userdata with other types

Ivo Beltchev

> Personally, I like "cumbersome" code very much. To the reader, it
> clearly tells what you want to do (check if the object has a property
> "mass" and if it has, compare it).
>
> Regards,
> Matthias
>  
The coder in me tends to agree. However this system is intended to be
used by non-programmers and should be as simple and as robust as
possible. For example I have a text box where they can type a criteria
for searching objects. The text can be as simple as "return obj.mass>20"
(give me all objects that have a mass>20). I want to minimize the
possibility for syntax and runtime errors.


Ivo

Reply | Threaded
Open this post in threaded view
|

Re: Comparing userdata with other types

Ralph Hempel
Ivo Beltchev wrote:
> The coder in me tends to agree. However this system is intended to be
> used by non-programmers and should be as simple and as robust as
> possible. For example I have a text box where they can type a criteria
> for searching objects. The text can be as simple as "return obj.mass>20"
> (give me all objects that have a mass>20). I want to minimize the
> possibility for syntax and runtime errors.

Don't metatables for userdata give you a hand here?

you make __index for the object return nil or some other marker
so that you can determine if the object has the property first.

If not, then you don't do the compare.

When the user types "return obj.mass>20" they are really asking
two questions:

1. Does this object have a mass
2. Is the mass > 20

Ralph