Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable name length vs performance

How is it possible, that a huge difference in variable name length won't cause any performance loss in javascript?

It takes the same time to declare var a = 0; as it takes to declare var aaaaaaaaaaaaaaa = 0; It takes the same time even to execute computations with them.

My fiddle to demonstrate

like image 744
István Pálinkás Avatar asked Jul 30 '15 09:07

István Pálinkás


People also ask

Should variable names be long?

Descriptive variable names should be between 8-20 characters. This is not a restriction, but just a guideline for the length of variable names. If it's too long, then it's really hard to type. If it's too short, it may not be descriptive enough.

Should you shorten variable names?

Don't shorten names unless you really need to. It really only makes sense if the variable name is already super long. For example, con is a popular abbreviation for a network connection, but it could also mean a drawback (pro vs con), or the end of an array.

Does the length of a name matter in programming?

The general rule of thumb is to make your variable names as short as possible whilst maintaining maximum clarity. It's a balancing act between clarity and length that, all too often, juvenile programmers will tip in the wrong direction.

Does variable name length affect memory?

The longer variable names are, the bigger the code is. This in turn requires more memory to work with it. For most intents and purposes, variable names do not impact memory or runtime significantly, however.


1 Answers

window.a = 2;
window.b = 3;
window.c = 4;
window.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 2;
window.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = 3;
window.ccccccccccccccccccccccccccccccccccccccccccccccccc = 4;    
var ts = [];

var t = performance.now();
for(var i = 0; i < 1000000; ++i) {
    a = b + c;
}
ts.push(performance.now() - t);

var t = performance.now();
for(var i = 0; i < 1000000; ++i) {
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb+ ccccccccccccccccccccccccccccccccccccccccccccccccc;
}
ts.push(performance.now() - t);

console.log(ts);

running the above 10 times in browser console gives me the following statistics, being a=b+c, a=b...+c... pairs:

[4.050000000046566, 4.614999999990687]
[4.254999999946449, 4.59499999997206]
[4.054999999993015, 4.584999999962747]
[4.869999999995343, 5.4500000000116415]
[4.074999999953434, 4.570000000006985]
[4.099999999976717, 4.775000000023283]
[4.205000000016298, 4.649999999965075]
[4.205000000016298, 4.669999999983702]
[4.159999999974389, 4.720000000030268]
[4.149999999965075, 4.684999999997672]

The longer version is ALWAYS slower.

in the case of local variables, this is different because they are compiled once and referred to using getlocal/setlocal instructions by index rather than by name. So let's see..

(function() {
    var a = 2;
    var b = 3;
    var c = 4;
    var aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 2;
    var bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = 3;
    var ccccccccccccccccccccccccccccccccccccccccccccccccc = 4;    
    var ts = [];

    var t = performance.now();
    for(var i = 0; i < 1000000; ++i) {
        a = b + c;
    }
    ts.push(performance.now() - t);

    var t = performance.now();
    for(var i = 0; i < 1000000; ++i) {
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb+ ccccccccccccccccccccccccccccccccccccccccccccccccc;
    }
    ts.push(performance.now() - t);

    console.log(ts);
})();

[2.5850000000791624, 2.2100000000791624] (longer wins)
[2.7950000000419095, 2.525000000023283] (shorter wins)
[2.4699999999720603, 2.4200000000419095] (longer wins)
[2.64000000001397, 2.2449999999953434] (longer wins)
[2.669999999925494, 2.469999999855645] (longer wins)
[2.5200000000186265, 2.7800000000279397] (shorter wins)
[2.4600000000791624, 2.3950000000186265] (longer wins)
[3.2900000001536682, 3.1299999998882413] (longer wins)
[3.1949999999487773, 3.1850000000558794] (longer wins)
[3.8049999999348074, 3.0200000000186265] (longer wins)

While they do vary quite surprisingly on most iterations, there are quite a few cases where the longer variable name was faster than the shorter variable name(a naive observer might conclude that the longer name makes it faster). This is because name was only relevant when the scope was being compiled; the instructions actually being executed do not refer to the variables by name.

My conclusion is; keep global variable names short, local variable names will slightly increase translation from text to instructions, but after this, it won't matter.

I assume javascript works similarly to actionscript in how it deals with variables so here's an actionscript dump of the two bytecodes side by side. (Adobe Flash CS3; decompiled with JPEXS free flash decompiler).

var a;
var b = 2;
var c = 3;
var aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
var bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2;
var ccccccccccccccccccccccccccccccccccccccccccccccccc = 3;    

function long_global()
{        
    for(var i = 0; i < 1000000; ++i) {
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ccccccccccccccccccccccccccccccccccccccccccccccccc;
    }
}

function short_global()
{
    for(var i = 0; i < 1000000; ++i) {
        a = b + c;
    }
}

function long_local()
{        
    var aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
    var bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2;
    var ccccccccccccccccccccccccccccccccccccccccccccccccc = 3;

    for(var i = 0; i < 1000000; ++i) {
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ccccccccccccccccccccccccccccccccccccccccccccccccc;
    }
}

function short_local()
{
    var a;
    var b = 2;
    var c = 3;

    for(var i = 0; i < 1000000; ++i) {
        a = b + c;
    }
}

long_global compiles to:

; d0
getlocal_0
; 30
pushscope
; 21
pushundefined
; 82
coerce_a
; d5
setlocal_1
; 24 00
pushbyte 0
; 82
coerce_a
; d5
setlocal_1
; 10 0e 00 00
jump ofs001b
; 09
ofs000d:label
; 5e 0a
findproperty Qname(PackageNamespace(""),"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
; 60 09
getlex Qname(PackageNamespace(""),"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
; 60 06
getlex Qname(PackageNamespace(""),"ccccccccccccccccccccccccccccccccccccccccccccccccc")
; a0
add
; 68 0a
initproperty Qname(PackageNamespace(""),"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
; d1
getlocal_1
; 91
increment
; 82
coerce_a
; d5
setlocal_1
; d1
ofs001b:getlocal_1
; 2d 01
pushint 1000000
; 15 eb ff ff
iflt ofs000d
; 47
returnvoid

short_global compiles to

; d0
getlocal_0
; 30
pushscope
; 21
pushundefined
; 82
coerce_a
; d5
setlocal_1
; 24 00
pushbyte 0
; 82
coerce_a
; d5
setlocal_1
; 10 0e 00 00
jump ofs001b
; 09
ofs000d:label
; 5e 08
findproperty Qname(PackageNamespace(""),"a")
; 60 05
getlex Qname(PackageNamespace(""),"b")
; 60 04
getlex Qname(PackageNamespace(""),"c")
; a0
add
; 68 08
initproperty Qname(PackageNamespace(""),"a")
; d1
getlocal_1
; 91
increment
; 82
coerce_a
; d5
setlocal_1
; d1
ofs001b:getlocal_1
; 2d 01
pushint 1000000
; 15 eb ff ff
iflt ofs000d
; 47
returnvoid

long_local:

; d0
getlocal_0
; 30
pushscope
; 21
pushundefined
; 82
coerce_a
; d5
setlocal_1
; 21
pushundefined
; 82
coerce_a
; d6
setlocal_2
; 21
pushundefined
; 82
coerce_a
; d7
setlocal_3
; 21
pushundefined
; 82
coerce_a
; 63 04
setlocal 4
; 24 02
pushbyte 2
; 82
coerce_a
; d6
setlocal_2
; 24 03
pushbyte 3
; 82
coerce_a
; d7
setlocal_3
; 24 00
pushbyte 0
; 82
coerce_a
; 63 04
setlocal 4
; 10 0c 00 00
jump ofs002c
; 09
ofs0020:label
; d2
getlocal_2
; d3
getlocal_3
; a0
add
; 82
coerce_a
; d5
setlocal_1
; 62 04
getlocal 4
; 91
increment
; 82
coerce_a
; 63 04
setlocal 4
; 62 04
ofs002c:getlocal 4
; 2d 01
pushint 1000000
; 15 ec ff ff
iflt ofs0020
; 47
returnvoid

short_local:

; d0
getlocal_0
; 30
pushscope
; 21
pushundefined
; 82
coerce_a
; d5
setlocal_1
; 21
pushundefined
; 82
coerce_a
; d6
setlocal_2
; 21
pushundefined
; 82
coerce_a
; d7
setlocal_3
; 21
pushundefined
; 82
coerce_a
; 63 04
setlocal 4
; 24 02
pushbyte 2
; 82
coerce_a
; d6
setlocal_2
; 24 03
pushbyte 3
; 82
coerce_a
; d7
setlocal_3
; 24 00
pushbyte 0
; 82
coerce_a
; 63 04
setlocal 4
; 10 0c 00 00
jump ofs002c
; 09
ofs0020:label
; d2
getlocal_2
; d3
getlocal_3
; a0
add
; 82
coerce_a
; d5
setlocal_1
; 62 04
getlocal 4
; 91
increment
; 82
coerce_a
; 63 04
setlocal 4
; 62 04
ofs002c:getlocal 4
; 2d 01
pushint 1000000
; 15 ec ff ff
iflt ofs0020
; 47
returnvoid

the byte code size of long_global and short_global; and short_local and long_local respectively are equivelent, however in local case, they are not referenced by name, only by setlocal and getlocal; whereas in global case, they are referenced by index of where the string key is; my guess is that the longer one takes longer to hash to get the referent, whereas the shorter one takes shorter to hash to get the referent before it can be used.

like image 134
Dmitry Avatar answered Oct 06 '22 20:10

Dmitry