Page 1 of 1

global constants in the name of efficiency

Posted: Mon Feb 13, 2012 7:46 pm
by Benamas
word on the street is that there are no constants in Lua like there are in C because there is in fact no pre-processing going on

that makes it probably a tradeoff between readable code and efficient code, since i also hear that global variables in Lua are looked up in some sort of table everytime they're accessed

the question is this: is the difference actually going to matter if i define a bunch of stuff in love.load (TILE_FLOOR = 0, TILE_WALL = 1, TILE_DOOR = 2, etc etc etc) versus using inscrutable numbers throughout my code

Re: global constants in the name of efficiency

Posted: Mon Feb 13, 2012 7:49 pm
by tentus
The difference will be that one will be legible in a week, and the other won't.

Lua is dang fast, looking up global variables is not going to be your bottleneck, and it's not worth worrying about performance until you do have a significant problem anyhow. Define clearly named variables now and you'll be glad that you did later.

Re: global constants in the name of efficiency

Posted: Mon Feb 13, 2012 9:30 pm
by Robin
Globals before magic numbers any time!

You might also want to consider using strings ("floor", "wall", "door") if it is applicable. That way, you have descriptive names without global lookups.

Re: global constants in the name of efficiency

Posted: Mon Feb 13, 2012 9:51 pm
by Mud
Benamas wrote:i also hear that global variables in Lua are looked up in some sort of table
Yup. The global foo is _G['foo'] (or _ENV['foo'] in Lua 5.2).
Benamas wrote:is the difference actually going to matter if i define a bunch of stuff in love.load (TILE_FLOOR = 0, TILE_WALL = 1, TILE_DOOR = 2, etc etc etc) versus using inscrutable numbers throughout my code
You can use locals (e.g. local TILE_WALL = 1) which are implemented via array indexes rather than hash lookups.

But I would focus more on writing correct code and forget about small efficiencies in this case.

Re: global constants in the name of efficiency

Posted: Mon Feb 13, 2012 10:00 pm
by kikito
Ok some facts. From less important to more important:
  • Variables defined with local are fastest to access than global variables. They are only available within the scope where they are defined. That scope can be a file.
  • For a function, it is cheaper to access a parameter than it is to access a global variable
  • On the other hand, invoking a function with parameters takes more than invoking it with no parameters (the parameters have to be "piled up").
  • Most of the time, this doesn't matter.
Trying to make a program faster by using locals instead of globals, or viceversa, is like like trying to make a car faster by painting it with a lighter paint. Unless it is a very small car made mostly by paint, it doesn't really matter. Your energy would be better spent in the parts that matter: the engine, the weels, and so on.

In a regular program, the "parts that matter" vary. Here are some common examples (this is not a complete nor exhaustive list):
  • Loops. The most loops you have, the slower your program will be. Especially if you have nested loops.
  • Repeated calculations. Especially if they take too long to take.
  • Access to disk/external systems (network, slow APIs, like writing to an ImageData).
  • Doing too many things.
It is also worth noting that these changes should not be done willy-nilly. The bottlenecks should be identified by properly measuring their time (as opposed to "just imagining" how much time they take). Then they should be optimized. Otherwise you could spend your time optimizing something that already runs fast.

Re: global constants in the name of efficiency

Posted: Tue Feb 14, 2012 5:58 am
by ivan
Like robin said, it's usually better to use stings instead of globals - something like:

Code: Select all

if tile == "wall" then
Lua checks strings very quickly because it just compares their reference in memory.
Constant strings usually make your code more legible/maintainable too.
The major bottlenecks in Lua from my experience are memory allocation and misusing tables.
For example:

Code: Select all

sz = sz .. " string" -- allocates a new string and deferences another
Creating loads of tables each frame is not very good for performance either.
Trying to make a program faster by using locals instead of globals, or viceversa, is like like trying to make a car faster by painting it with a lighter paint
Yes, probably true, although another useful thing about locals is that they often make your code shorter/easier to read:

Code: Select all

   love.graphics.print("This text is not black", 100, 100)
   love.graphics.setColor(255,0,0)
   love.graphics.print("This text is red", 100, 200)
vs:

Code: Select all

   local lg = love.graphics
   lg.print("This text is not black", 100, 100)
   lg.setColor(255,0,0)
   lg.print("This text is red", 100, 200)

Re: global constants in the name of efficiency

Posted: Wed Feb 15, 2012 4:26 am
by Inny
When you lookup a variable stored in the global table, lua uses it's internal interned string format to perform the lookup. As mentioned before, TILE_GRASS is really just sugar syntax for _G["TILE_GRASS"]. Normally, this is really fast because of the interning that goes on, which means the strings are compared via reference, and all new strings created are first checked against an internal table to see if the string already exists so that the existing reference can be reused. This makes table lookup O(1) amortized, meaning for all intents and purposes, it requires no additional time regardless of the size of the table over the life of the program.

Essentially, using named constants are already efficient.

As a side trick, you can set the named constants to the same string as their name. That way, you can live in both worlds, i.e. using regular named constants everywhere it doesn't matter, but using the string representation if it has to happen in a tightly optimized inner loop.

Here's a freebie that does what I'm talking about:

Code: Select all

function constantify(...)
  for i = 1, select('#', ...) do
    local S = select(i, ...)
    _G[S] = S
  end
end

constantify( "APPLE", "BANANA", "CARROT" )
assert( APPLE == "APPLE" )

Re: global constants in the name of efficiency

Posted: Wed Feb 15, 2012 4:43 am
by hryx
This thread puts me at ease. I think I'll worry more about scope than efficiency now when deciding to declare a local variable.