Fast metamethods for Userdata types

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

Fast metamethods for Userdata types

Dibyendu Majumdar
Hi,

Apologies if this is going over old ground ... I have been thinking
about how to allow fast metamethods for userdata objects. As userdata
objects are created by C code then it is possible for C code to
provide an array of C functions (like a C++ vtable) for the userdata
object - the C functions to be used as metamethods.

What would be reason for not doing it this way?

I am interested in this as I want to achieve high performance for
certain operations involving userdata types - which otherwise means I
have to make the VM recognize these types so that it can perform
operations on these types natively. However that approach isn't
scalable as enhancing the VM to recognize new types is a lot of work.

Thanks and Regards

Dibyendu

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Rena
On Mon, Apr 6, 2015 at 7:36 PM, Dibyendu Majumdar
<[hidden email]> wrote:

> Hi,
>
> Apologies if this is going over old ground ... I have been thinking
> about how to allow fast metamethods for userdata objects. As userdata
> objects are created by C code then it is possible for C code to
> provide an array of C functions (like a C++ vtable) for the userdata
> object - the C functions to be used as metamethods.
>
> What would be reason for not doing it this way?
>
> I am interested in this as I want to achieve high performance for
> certain operations involving userdata types - which otherwise means I
> have to make the VM recognize these types so that it can perform
> operations on these types natively. However that approach isn't
> scalable as enhancing the VM to recognize new types is a lot of work.
>
> Thanks and Regards
>
> Dibyendu
>

I'm not sure what you're proposing. The metatable is already a list of
functions to call for various events. Are you suggesting that the
metamethods be stored in an array instead? I think Lua already does
something like that internally when you assign the metatable.

--
Sent from my Game Boy.

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Sean Conner
In reply to this post by Dibyendu Majumdar
It was thus said that the Great Dibyendu Majumdar once stated:
> Hi,
>
> Apologies if this is going over old ground ... I have been thinking
> about how to allow fast metamethods for userdata objects. As userdata
> objects are created by C code then it is possible for C code to
> provide an array of C functions (like a C++ vtable) for the userdata
> object - the C functions to be used as metamethods.
>
> What would be reason for not doing it this way?

  I assume you are talking about functions like __add() or __concat().

  Well, not all metamethods are functions.  __mode, __metatable and __name
(Lua 5.3) are never functions, while __index and __newindex can either be a
function or a table.  Most, however, are functions [1].

  For insance, "x = lpeg.P(1)" has the following metatable:

__mul    function: 0x77adf8  
__add    function: 0x77ad08  
__pow    function: 0x77ab04  
__div    function: 0x77a8c8  
__name   "lpeg-pattern"      
__unm    function: 0x77a84c  
__gc     function: 0x77b384  
__index  table: 0x9664278    
__sub    function: 0x77a6e8  
__len    function: 0x77aa94  

__index could just as easily have been a function (maybe not for LPeg but in
the general case).

  Also, metatables are used to provide functions (or fields) other than the
defined metamethod ones.  For instance, the metatable for io.stdout (again,
Lua 5.3):

__tostring  function: 0x8060888  
flush       function: 0x8061a00  
lines       function: 0x8060df0  
__name      "FILE*"              
seek        function: 0x80618a8  
write       function: 0x8061870  
setvbuf     function: 0x8061960  
__gc        function: 0x80609d8  
__index     table: 0x9654428      
close       function: 0x806098c  
read        function: 0x80615cc  

  The metatable is a nice place to cache all this.  

> I am interested in this as I want to achieve high performance for
> certain operations involving userdata types - which otherwise means I
> have to make the VM recognize these types so that it can perform
> operations on these types natively. However that approach isn't
> scalable as enhancing the VM to recognize new types is a lot of work.

  What type of high performance are you expecting?  Outside of numbers and
strings, trying to get high performance out of metamethods with userdata
just doesn't seem to make sense to me.  LPeg is perhaps the worse-case
scenario here (which to me, makes it the best place to start) as the '*'
operator isn't multiplcation (it's more of an "and" operation but not
commutative).

  -spc

[1] A table I constructed for my own use, and may be useful here:

               5.1     5.2     5.3     function
__add           *       *       *       a + b
__sub           *       *       *       a - b
__mul           *       *       *       a * b
__div           *       *       *       a / b
__mod           *       *       *       a % b
__pow           *       *       *       a ^ b
__umn           *       *       *       -a
__idiv                          *       a // b
__band                          *       a & b
__bor                           *       a | b
__bxor                          *       a ~ b
__bnot                          *       ~a
__shl                           *       a << b
__shr                           *       a >> b
__concat        *       *       *       a .. b
__len           *       *       *       #a
__eq            *       *       *       a == b
__lt            *       *       *       a < b
__le            *       *       *       a > b
__index         *       *       *       a = b[]         can be table
__newindex      *       *       *       a[] = b         can be table
__call          *       *       *       a()
__gc            *       *       *
__mode          *       *       *                       string
__metatable     *       *       *                       table
__tostring      *       *       *
__ipairs                *
__pairs                 *       *
__name                          *                       string


Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Nagaev Boris
On Tue, Apr 7, 2015 at 6:14 AM, Sean Conner <[hidden email]> wrote:
>   Well, not all metamethods are functions.  __mode, __metatable and __name
> (Lua 5.3) are never functions, while __index and __newindex can either be a
> function or a table.  Most, however, are functions [1].

Thank you, I didn't know that all fields of a metatable are called
metamethods. I thounght that only a function can be a metamethod. I
found the proof in Lua manual:

> We call the keys in a metatable events and the values metamethods.

By the way, "closure" was another Lua definition I misunderstood. I
thought that closure is a function instance which uses external local
variables. However this is also wrong. Lua manual says as follows:

> A function definition is an executable expression, whose
> value has type function. When Lua pre-compiles a chunk, all
> its function bodies are pre-compiled too. Then, whenever
> Lua executes the function definition, the function is
> instantiated (or closed). This function instance (or
> closure) is the final value of the expression. Different
> instances of the same function can refer to different
> external local variables and can have different environment
> tables.

So, if I understand correctly, any function instance is called closure.

> [1]     A table I constructed for my own use, and may be useful here:
>
>                5.1     5.2     5.3     function
> __add           *       *       *       a + b
> __sub           *       *       *       a - b
> __mul           *       *       *       a * b
> __div           *       *       *       a / b
> __mod           *       *       *       a % b
> __pow           *       *       *       a ^ b
> __umn           *       *       *       -a
> __idiv                          *       a // b
> __band                          *       a & b
> __bor                           *       a | b
> __bxor                          *       a ~ b
> __bnot                          *       ~a
> __shl                           *       a << b
> __shr                           *       a >> b
> __concat        *       *       *       a .. b
> __len           *       *       *       #a
> __eq            *       *       *       a == b
> __lt            *       *       *       a < b
> __le            *       *       *       a > b
> __index         *       *       *       a = b[]         can be table
> __newindex      *       *       *       a[] = b         can be table
> __call          *       *       *       a()
> __gc            *       *       *
> __mode          *       *       *                       string
> __metatable     *       *       *                       table
> __tostring      *       *       *
> __ipairs                *
> __pairs                 *       *
> __name                          *                       string

Thank you for this nice table. I've converted it into Markdown [1]

[1] https://github.com/starius/helpme/blob/master/lua-metamethods.md

Best regards,
Boris Nagaev

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Roberto Ierusalimschy
> By the way, "closure" was another Lua definition I misunderstood. I
> thought that closure is a function instance which uses external local
> variables. However this is also wrong. Lua manual says as follows:
>
> > A function definition is an executable expression, whose
> > value has type function. When Lua pre-compiles a chunk, all
> > its function bodies are pre-compiled too. Then, whenever
> > Lua executes the function definition, the function is
> > instantiated (or closed). This function instance (or
> > closure) is the final value of the expression. Different
> > instances of the same function can refer to different
> > external local variables and can have different environment
> > tables.
>
> So, if I understand correctly, any function instance is called closure.

Yes. The point is that, when a closure has no external variables, the
difference between the closure and the "function" (or "prototype", as
it is called in the source code) is very thin. (In fact, in the current
implementation, there is a 1-1 correspondence between closures and
functions when there are no external variables.)

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Dibyendu Majumdar
In reply to this post by Sean Conner
On 7 April 2015 at 07:14, Sean Conner <[hidden email]> wrote:
>> Apologies if this is going over old ground ... I have been thinking
>> about how to allow fast metamethods for userdata objects. As userdata
>> objects are created by C code then it is possible for C code to
>> provide an array of C functions (like a C++ vtable) for the userdata
>> object - the C functions to be used as metamethods.
>>
>> What would be reason for not doing it this way?
>
>   I assume you are talking about functions like __add() or __concat().

Yes but more importantly __index method.

>   Also, metatables are used to provide functions (or fields) other than the
> defined metamethod ones.  For instance, the metatable for io.stdout (again,
> Lua 5.3):
>
> __tostring  function: 0x8060888
> flush       function: 0x8061a00
> lines       function: 0x8060df0
> __name      "FILE*"
> seek        function: 0x80618a8
> write       function: 0x8061870
> setvbuf     function: 0x8061960
> __gc        function: 0x80609d8
> __index     table: 0x9654428
> close       function: 0x806098c
> read        function: 0x80615cc
>
>   The metatable is a nice place to cache all this.

Right - but isn't that even worse for performance - i.e. more chances
of hash collision?

>> I am interested in this as I want to achieve high performance for
>> certain operations involving userdata types - which otherwise means I
>> have to make the VM recognize these types so that it can perform
>> operations on these types natively. However that approach isn't
>> scalable as enhancing the VM to recognize new types is a lot of work.
>
>   What type of high performance are you expecting?  Outside of numbers and
> strings, trying to get high performance out of metamethods with userdata
> just doesn't seem to make sense to me.  LPeg is perhaps the worse-case
> scenario here (which to me, makes it the best place to start) as the '*'
> operator isn't multiplcation (it's more of an "and" operation but not
> commutative).

I am thinking of structures such as vectors and matrices. Agree that
__add() probably doesn't matter so much as the addition itself will be
expensive. But performance of __index matters. Now if you think of
Ravi where the [] operator on an array is specialized - and executed
inline for gets, then the cost of a hash table lookup and then going
through the mechanism for a function call is enormous. I will try to
do a benchmark at some point to investigate how much performance loss
really occurs but my guess is that it is not insignificant.

Of course even if a C vtable could be provided that only saves the
cost of hash table lookup so the other cost is still there so in the
end the gains would be small, so I also think a generic solution is
hard.

I believe (reading the paper on evolution of Lua) that the current
approach is chosen for its simplicity and the fact that it reuses the
table infrastructure, but I could be wrong.

Regards
Dibyendu

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Javier Guerra Giraldez
On Tue, Apr 7, 2015 at 3:50 PM, Dibyendu Majumdar
<[hidden email]> wrote:
> Now if you think of
> Ravi where the [] operator on an array is specialized - and executed
> inline for gets, then the cost of a hash table lookup and then going
> through the mechanism for a function call is enormous.


In LuaJIT, methametods are added to ffi objects using the
`ffi.metatype(ct, metatable)`, where `ct` is the ffi type and
`metatable` is compatible with the plain Lua metatable.  But the user
is not allowed to modify the metatable, its contents, or it's __index
contents after the call to metatype().

I guess that allows LuaJIT to statically set all the function
bindings, and the result is that adding simple methods to ffi objects
is _very_ efficient, and typically gets fully compiled.


--
Javier

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Dibyendu Majumdar
On 7 April 2015 at 22:01, Javier Guerra Giraldez <[hidden email]> wrote:
> In LuaJIT, methametods are added to ffi objects using the
> `ffi.metatype(ct, metatable)`, where `ct` is the ffi type and
> `metatable` is compatible with the plain Lua metatable.  But the user
> is not allowed to modify the metatable, its contents, or it's __index
> contents after the call to metatype().
>
> I guess that allows LuaJIT to statically set all the function
> bindings, and the result is that adding simple methods to ffi objects
> is _very_ efficient, and typically gets fully compiled.

That's very interesting ... so essentially it is allowing user to
define metatable only once - no changes allowed, so then it is free to
optimise the way the metatable is used?

Re compilation - I suspect LuaJIT also uses a more efficient call
mechanism? In Ravi all calls go via luaD_precall() / luaD_call() so it
may not be as optimum.

Regards
Dibyeneu

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Javier Guerra Giraldez
On Tue, Apr 7, 2015 at 4:11 PM, Dibyendu Majumdar
<[hidden email]> wrote:
> That's very interesting ... so essentially it is allowing user to
> define metatable only once - no changes allowed, so then it is free to
> optimise the way the metatable is used?


i guess that's the motivation for the restriction: since it knows the
methods won't change, it's free to do the table fetch only once and
compile a straight function call (which could even be flattened away
by the trace compiler)

--
Javier

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Dibyendu Majumdar
On 7 April 2015 at 22:25, Javier Guerra Giraldez <[hidden email]> wrote:

>> That's very interesting ... so essentially it is allowing user to
>> define metatable only once - no changes allowed, so then it is free to
>> optimise the way the metatable is used?
>
>
> i guess that's the motivation for the restriction: since it knows the
> methods won't change, it's free to do the table fetch only once and
> compile a straight function call (which could even be flattened away
> by the trace compiler)
>

Of course, in the FFI worldview the metamethods would be written in
Lua, so they could be completely inlined by LuaJIT.
Thanks for the insight - gives me food for thought. Although I use
LuaJIT I don't use FFI, so am not familiar with the ins/outs of FFI.

Regards
Dibyendu

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Rena
In reply to this post by Sean Conner
On Tue, Apr 7, 2015 at 2:14 AM, Sean Conner <[hidden email]> wrote:

> It was thus said that the Great Dibyendu Majumdar once stated:
>> Hi,
>>
>> Apologies if this is going over old ground ... I have been thinking
>> about how to allow fast metamethods for userdata objects. As userdata
>> objects are created by C code then it is possible for C code to
>> provide an array of C functions (like a C++ vtable) for the userdata
>> object - the C functions to be used as metamethods.
>>
>> What would be reason for not doing it this way?
>
>   I assume you are talking about functions like __add() or __concat().
>
>   Well, not all metamethods are functions.  __mode, __metatable and __name
> (Lua 5.3) are never functions, while __index and __newindex can either be a
> function or a table.  Most, however, are functions [1].
>
>   For insance, "x = lpeg.P(1)" has the following metatable:
>
> __mul    function: 0x77adf8
> __add    function: 0x77ad08
> __pow    function: 0x77ab04
> __div    function: 0x77a8c8
> __name   "lpeg-pattern"
> __unm    function: 0x77a84c
> __gc     function: 0x77b384
> __index  table: 0x9664278
> __sub    function: 0x77a6e8
> __len    function: 0x77aa94
>
> __index could just as easily have been a function (maybe not for LPeg but in
> the general case).
>
>   Also, metatables are used to provide functions (or fields) other than the
> defined metamethod ones.  For instance, the metatable for io.stdout (again,
> Lua 5.3):
>
> __tostring  function: 0x8060888
> flush       function: 0x8061a00
> lines       function: 0x8060df0
> __name      "FILE*"
> seek        function: 0x80618a8
> write       function: 0x8061870
> setvbuf     function: 0x8061960
> __gc        function: 0x80609d8
> __index     table: 0x9654428
> close       function: 0x806098c
> read        function: 0x80615cc
>
>   The metatable is a nice place to cache all this.
>
>> I am interested in this as I want to achieve high performance for
>> certain operations involving userdata types - which otherwise means I
>> have to make the VM recognize these types so that it can perform
>> operations on these types natively. However that approach isn't
>> scalable as enhancing the VM to recognize new types is a lot of work.
>
>   What type of high performance are you expecting?  Outside of numbers and
> strings, trying to get high performance out of metamethods with userdata
> just doesn't seem to make sense to me.  LPeg is perhaps the worse-case
> scenario here (which to me, makes it the best place to start) as the '*'
> operator isn't multiplcation (it's more of an "and" operation but not
> commutative).
>
>   -spc
>

I suppose you might see some performance gain (at the cost of memory)
by having an array associated with each userdata, which stores
pointers to C functions for each metamethod at particular indexes.
(e.g. metamethods[0] is __index, metamethods[1] is __newindex, etc.)
If the pointer is NULL, then you look in the metatable. That would be
something Lua could manage internally when you set or modify the
metatable.

Someone would have to try it and see if there's any significant
performance gain. It could be implemented as a compile-time option.

--
Sent from my Game Boy.

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Dibyendu Majumdar
On 7 April 2015 at 23:43, Rena <[hidden email]> wrote:

> I suppose you might see some performance gain (at the cost of memory)
> by having an array associated with each userdata, which stores
> pointers to C functions for each metamethod at particular indexes.
> (e.g. metamethods[0] is __index, metamethods[1] is __newindex, etc.)
> If the pointer is NULL, then you look in the metatable. That would be
> something Lua could manage internally when you set or modify the
> metatable.
>
> Someone would have to try it and see if there's any significant
> performance gain. It could be implemented as a compile-time option.

Yes that is what I was thinking of. In the evolution of Lua perhaps
this has already been tried, tested and discarded as not beneficial,
hence my point about possibly going over old ground.

I think there are two issues:
a) reducing the cost of lookup
b) reducing the cost of function call

The latter is much harder I suspect as any function call must go
through the Lua stack. In very specific cases maybe this could be
avoided - e.g. performing a get on an array, but in general the stack
discipline is important for the garbage collector as described in Lua
papers.

But it is a interesting problem nevertheless.

One solution is to create additional types and let the VM recognize
these types. I am particularly interested in vectors and matrices. But
at the same time I am interested in compatibility with Lua so not sure
how I can achieve both. Perhaps provide a slower metatable based
implementation for standard Lua, and a faster native implementation in
Ravi?

Regards
Dibyendu

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Soni "They/Them" L.


On 07/04/15 08:07 PM, Dibyendu Majumdar wrote:

> On 7 April 2015 at 23:43, Rena <[hidden email]> wrote:
>> I suppose you might see some performance gain (at the cost of memory)
>> by having an array associated with each userdata, which stores
>> pointers to C functions for each metamethod at particular indexes.
>> (e.g. metamethods[0] is __index, metamethods[1] is __newindex, etc.)
>> If the pointer is NULL, then you look in the metatable. That would be
>> something Lua could manage internally when you set or modify the
>> metatable.
>>
>> Someone would have to try it and see if there's any significant
>> performance gain. It could be implemented as a compile-time option.
> Yes that is what I was thinking of. In the evolution of Lua perhaps
> this has already been tried, tested and discarded as not beneficial,
> hence my point about possibly going over old ground.
>
> I think there are two issues:
> a) reducing the cost of lookup
> b) reducing the cost of function call
>
> The latter is much harder I suspect as any function call must go
> through the Lua stack. In very specific cases maybe this could be
> avoided - e.g. performing a get on an array, but in general the stack
> discipline is important for the garbage collector as described in Lua
> papers.
Well it /could/ in theory leave the stack uninitalized and
initialize/allocate as needed?

>
> But it is a interesting problem nevertheless.
>
> One solution is to create additional types and let the VM recognize
> these types. I am particularly interested in vectors and matrices. But
> at the same time I am interested in compatibility with Lua so not sure
> how I can achieve both. Perhaps provide a slower metatable based
> implementation for standard Lua, and a faster native implementation in
> Ravi?
>
> Regards
> Dibyendu
>

--
Disclaimer: these emails are public and can be accessed from <TODO: get a non-DHCP IP and put it here>. If you do not agree with this, DO NOT REPLY.


Reply | Threaded
Open this post in threaded view
|

Upvalue efficiency [was: Fast metamethods for Userdata types]

David Favro
In reply to this post by Roberto Ierusalimschy
On 04/07/2015 08:07 AM, Roberto Ierusalimschy wrote:
> Yes. The point is that, when a closure has no external variables, the
> difference between the closure and the "function" (or "prototype", as
> it is called in the source code) is very thin. (In fact, in the current
> implementation, there is a 1-1 correspondence between closures and
> functions when there are no external variables.)

This reminds me of a coding-style question that comes up often for me.  It
amounts to, which is the "better" way to get data into a function, accessing
an upvalue or passing in a parameter, especially when the use of the
function is localized such as a function defined within another.  My
definition of "better" is typically run-time efficiency when the function is
called many times, but I'd be interested in opinions of style as well.  I
sometimes superstitiously think that there may be some "advantage" in
creating a function that has no external references rather than one which
requires separate closures, but I honestly have no idea if this is true.

I suppose there are two cases, depending on how often the parameter data is
changed, i.e. is the upvalue's value set prior to each function-call or does
its value remain the same across many calls.  An example of the latter case:

-- Given:
local foo = {};

-- Is this faster:
local function bar1( x )
     foo[#foo+1] = x;
end
for i = 1, 1000000 do
     bar1( "boo" );
end

-- Or this?
local function bar2( tbl, x )
     tbl[#tbl+1] = x;
end
for i = 1, 1000000 do
     bar2( foo, "boo" );
end


Reply | Threaded
Open this post in threaded view
|

Re: Upvalue efficiency [was: Fast metamethods for Userdata types]

Sean Conner
It was thus said that the Great David Favro once stated:
>
> I sometimes superstitiously think that there may be some "advantage" in
> creating a function that has no external references rather than one which
> requires separate closures, but I honestly have no idea if this is true.

  I can think of two advantages:

        1) it's easier to serialize such a function, as it relies on no
           external data.
        2) it's easier to test such a function as it relies on no external
           data.

  -spc

Reply | Threaded
Open this post in threaded view
|

Re: Upvalue efficiency [was: Fast metamethods for Userdata types]

Patrick Donnelly
On Wed, Apr 8, 2015 at 11:48 AM, Sean Conner <[hidden email]> wrote:

> It was thus said that the Great David Favro once stated:
>>
>> I sometimes superstitiously think that there may be some "advantage" in
>> creating a function that has no external references rather than one which
>> requires separate closures, but I honestly have no idea if this is true.
>
>   I can think of two advantages:
>
>         1) it's easier to serialize such a function, as it relies on no
>            external data.
>         2) it's easier to test such a function as it relies on no external
>            data.

and here are some disadvantages:

1) You force the caller to maintain references to data that is
ancillary or not useful.
2) The function parameters explode and any new data dependency may
require updating all calls to the function.
3) Data dependencies expressed using control structures (e.g. the loop
variable in a numeric for loop) require wrapping function references
with its dependencies. The Python analogue for this is
functools.partial (and they actually need this because Python does not
know how to do scoping/bindings).

--
Patrick Donnelly

Reply | Threaded
Open this post in threaded view
|

Re: Fast metamethods for Userdata types

Stephan Hennig-2
In reply to this post by Sean Conner
Am 07.04.2015 um 07:14 schrieb Sean Conner:

> [1] A table I constructed for my own use, and may be useful here:
>
>                5.1     5.2     5.3     function
> __add           *       *       *       a + b
> __sub           *       *       *       a - b
> __mul           *       *       *       a * b
> __div           *       *       *       a / b
> __mod           *       *       *       a % b
> __pow           *       *       *       a ^ b
> __umn           *       *       *       -a
> __idiv                          *       a // b
> __band                          *       a & b
> __bor                           *       a | b
> __bxor                          *       a ~ b
> __bnot                          *       ~a
> __shl                           *       a << b
> __shr                           *       a >> b
> __concat        *       *       *       a .. b
> __len           *       *       *       #a
> __eq            *       *       *       a == b
> __lt            *       *       *       a < b
> __le            *       *       *       a > b

Nice table!  Two remarks:

If writing 'a > b' here instead of 'a <= b' is meant as a translation
to a one character operator, a negation is missing: not (a > b).

But then again, __le is needed in the first place just because '<='
cannot be expressed by '<' in the general case.  To quote from PiL,
<URL:http://www.lua.org/pil/13.2.html>:

> (Big parentheses: Until Lua 4.0, all order operators were translated
> to a single one, by translating a <= b to not (b < a). However, this
> translation is incorrect when we have a partial order, that is, when
> not all elements in our type are properly ordered. For instance,
> floating-point numbers are not totally ordered in most machines,
> because of the value Not a Number (NaN). According to the IEEE 754
> standard, currently adopted by virtually every hardware, NaN
> represents undefined values, such as the result of 0/0. The standard
> specifies that any comparison that involves NaN should result in
> false. That means that NaN <= x is always false, but x < NaN is also
> false. That implies that the translation from a <= b to not (b < a)
> is not valid in this case.)

So, better write it out in full length:

  __le            *       *       *       a <= b

Best regards,
Stephan Hennig


Reply | Threaded
Open this post in threaded view
|

Re: Upvalue efficiency [was: Fast metamethods for Userdata types]

Tim Hill
In reply to this post by David Favro

> On Apr 8, 2015, at 7:15 AM, David Favro <[hidden email]> wrote:
>
> This reminds me of a coding-style question that comes up often for me.  It amounts to, which is the "better" way to get data into a function, accessing an upvalue or passing in a parameter, especially when the use of the function is localized such as a function defined within another.  My definition of "better" is typically run-time efficiency when the function is called many times, but I'd be interested in opinions of style as well.  I sometimes superstitiously think that there may be some "advantage" in creating a function that has no external references rather than one which requires separate closures, but I honestly have no idea if this is true.
>

I don’t think this is really a “better/worse” thing as upvalues and arguments are different in several respects. First, an upvalue has a lifetime that extends across all calls to the closure. Second, parameters are visible at the “point of call” and are therefore known to the caller. So a pretty simple rule is: If the data is local to a single call, it’s a parameter, if it extends across calls, it might be better as an upvalue.

—Tim