global constants in the name of efficiency

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
Benamas
Prole
Posts: 28
Joined: Wed Apr 14, 2010 10:23 pm

global constants in the name of efficiency

Post by Benamas » Mon Feb 13, 2012 7:46 pm

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

User avatar
tentus
Inner party member
Posts: 1060
Joined: Sun Oct 31, 2010 7:56 pm
Location: Appalachia
Contact:

Re: global constants in the name of efficiency

Post by tentus » Mon Feb 13, 2012 7:49 pm

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.
Kurosuke needs beta testers

User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: global constants in the name of efficiency

Post by Robin » Mon Feb 13, 2012 9:30 pm

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.
Help us help you: attach a .love.

User avatar
Mud
Citizen
Posts: 98
Joined: Fri Nov 05, 2010 4:54 am

Re: global constants in the name of efficiency

Post by Mud » Mon Feb 13, 2012 9:51 pm

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.

User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: global constants in the name of efficiency

Post by kikito » Mon Feb 13, 2012 10:00 pm

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.
When I write def I mean function.

User avatar
ivan
Party member
Posts: 1548
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: global constants in the name of efficiency

Post by ivan » Tue Feb 14, 2012 5:58 am

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)

User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: global constants in the name of efficiency

Post by Inny » Wed Feb 15, 2012 4:26 am

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" )

User avatar
hryx
Party member
Posts: 110
Joined: Mon Mar 29, 2010 2:28 am
Location: SF<CA<USA

Re: global constants in the name of efficiency

Post by hryx » Wed Feb 15, 2012 4:43 am

This thread puts me at ease. I think I'll worry more about scope than efficiency now when deciding to declare a local variable.

Post Reply

Who is online

Users browsing this forum: No registered users and 15 guests