Rodmentou
Rodmentou

Reputation: 1640

What is better: to create a new variable or to assign the value to an object field?

I wish to know what would be faster to implement.

I want to have a temporary variable that will be used for some calculations inside a function. The attacker and defender objects will be later used and everything created inside them should be deleted.

First, I have an approach of creating a temporary dmg variable to store the damages of attacker and defender.

                    var dmg;
                    dmg.attacker = 10;
                    dmg.defender = 10;           
                    var battle = function (dmg, attacker, defender) {
                        //Some calculations using dmg.attacker and dmg.defender.        
                    }

And a second approach, were I'm storing attacker and defender dmg inside them. There will be no problem if other part of the program catchs the attacker/defender object before the dmg has been deleted.

                    attacker.dmg = 10;
                    defender.dmg = 10;
                    var battle = function (attacker, defender) {
                        //Some calculations using attacker.dmg and defender.dmg.
                        delete attacker.dmg;
                        delete defender.dmg;                            
                    }

So, which implementation would be faster and why? Is there any other better options? I'm using Node 4 LTS, it there any nuances that I don't know about?

Upvotes: 1

Views: 423

Answers (2)

Alexander Elgin
Alexander Elgin

Reputation: 6956

According to the result of the snippet below the first approach is much faster.

var dmg = {};
var battleDmg = function (dmg) {};

var start = new Date().getTime();
for(var i = 0; i < 100000; i++) {
	dmg.attacker = 10;
	dmg.defender = 10;
	battleDmg(dmg);
}
console.log('dmg:' + (new Date().getTime() - start));

var attacker = {}, defender = {};
var battleAttackerVsDefender = function (attacker, defender) {
	delete attacker.dmg;
	delete defender.dmg;                            
};

start = new Date().getTime();
for(i = 0; i < 100000; i++) {
	attacker.dmg = 10;
	defender.dmg = 10;
	battleAttackerVsDefender(attacker, defender);
}
console.log('a vs d:' + (new Date().getTime() - start));

I think it is because in the first case:

  1. a single argument (instead of 2 arguments) is passed to the function
  2. no delete operation (instead of 2 operations) is performed

Upvotes: 2

user4842163
user4842163

Reputation:

This is not the kind of thing for which performance should be the ultimate guiding factor, especially without a profiler in hand. Let maintainability and productivity be the guiding force here until you start measuring hotspots in hindsight.

That said, just as a general rule of thumb, the more local your state changes and accesses are, typically the faster they will be. More local accesses to local variables are preferable from a performance standpoint than more access to fewer but more global variables.

Local State is Fast

Optimizing compilers do their best when the most amount of information is readily available. Effective register allocation and instruction selection is easier when analyzing the local variables of a function than globals variables with a much broader scope than the function which could be modified and accessed anywhere.

The key to efficiency often revolves around loading from slower but bigger memory (DRAM,e.g.) into faster but smaller memory (L1 cache line and then register). Making code fast means keeping and using frequently-accessed memory as much as possible inside those faster but smaller forms of memory (register, e.g.). This is easier for the compiler to do when your variables have a very local scope, since it doesn't have to look outside that scope to see whether it needs to spill the variable to the stack or can keep it inside the register, for example.

So as a general rule of thumb, prefer more local state with shorter scopes to more global states with wider scopes. That not only tends to improve efficiency but also reduce human errors*.

* Note that this is opposite from an assembly mindset. In assembly, it's helpful to reuse registers as much as possible to avoid stack spills. In languages that have variables instead of direct register access, more local variables helps the compiler figure out what registers it can reuse.

Specific Example

In this specific case, adding members and removing them from an associative structure (objects fit this case in JS) tends to be more expensive than creating one and simply discarding it as a whole. These lines:

delete attacker.dmg;
delete defender.dmg;

... specifically tend to be more costly than constructing some temporary object and simply destroying it as a whole when you're finished with it than adding members to a more global object and then removing them when done.

As a plus, this should also be a little less error-prone so you get that bonus as well. As a second plus, assuming attacker and defender have a fairly broad scope, this function that creates this dmg variable would avoid side effects to those objects, and therefore would be thread-safe since it's only dealing with local states (assuming this is all it's doing and not modifying other globals).

If you're really fussy about it, it would be best to create attacker damage and defender damage as two separate scalars instead of aggregated into an object and pass both forms of damage to this battle function. But that's really degrading the code readability, and something you should only do with a profiler in your hand that tells you this is a top hotspot.

Upvotes: 3

Related Questions