News for hackers. Stuff that matters.
Re:Python Patterns - An Optimization Anecdote by nene on Tuesday November 02, 2010 @07:10AM (#1859927)
I decided to try writing the same thing in JavaScript and discovered something really strange.

My first idea was:

    numbers.map(function(x){return String.fromCharCode(x);}).join("");
This was pretty fast already, but why not eliminate the anonymous function completely and pass String.fromCharCode directly to map():

    numbers.map(String.fromCharCode).join("");
I timed it and... ...this was ~100 times slower than the previous version. WTF!

Somehow passing this native function directly to Array.map() is way slower than wrapping it inside another function and passing that to Array.map().

I have tested it so far in Chrome, Firefox and Opera - the results are the same. I also tried forEach(), which behaves similarly.

Does anybody have an idea why this is so?

Update: I tried the same with Math.round and Math.sin, and with these the results were as one would expect: passing the function to Array.map() directly was a little bit faster than using intermediate anonymous function. So it seems the problem is with String.fromCharCode specifically.

Re:Python Patterns - An Optimization Anecdote by nene on Tuesday November 02, 2010 @10:27AM (#1860516)
Found an answer.

The problem is that String.fromCharCode takes multiple arguments and Array.map also passes multiple arguments to the callback, therefore the equivalent of numbers.map(String.fromCharCode) is actually:

    numbers.map(function(x, y, z){return String.fromCharCode(x, y, z);})
Which of course is slower as the end result will actually be array with longer strings in it.
Re:Python Patterns - An Optimization Anecdote by lysium on Tuesday November 02, 2010 @07:21AM (#1859959)
Just a guess: your anonymous function cannot be redefined (because there is no name), but String.fromCharCode could potentially be. Thus, a similar reason as mentioned in the article for global vs. local variables.

One would think that String.fromCharCode is looked up only once, though.

Re:Python Patterns - An Optimization Anecdote by pornel on Tuesday November 02, 2010 @09:26AM (#1860301)
Actually it's the opposite. When you pass String.fromCharCode directly, then you're passing reference (not name) to that particular implementation, and it can't change.

When you pass anonymous function, then every execution of that function needs to look up `String.fromCharCode` (anonymous functions save scope, not references).

I'm surprised by the benchmark as well. I suspect it may be because calls to native functions are handled differently from calls to JS functions, and JS engine is able to optimize call inside anonymous function (create trace/JIT and inline it), but not when calling by reference (and perhaps keeps calling it by some expensive proxy object).

Re:Python Patterns - An Optimization Anecdote by nene on Tuesday November 02, 2010 @07:27AM (#1859975)
That's exactly what I was thinking:

* In the first version each time the anonymous function is executed interpreter has to lookup String and from it the fromCharCode method => 2n lookups.

* In the second version the String and fromCharCode have to be lookud up only once => 2 lookups.

Therefore according to slow-lookups-theory the first version should be slower. Except when I measure it, the opposite turns out to be true.

Re:Python Patterns - An Optimization Anecdote by dish on Tuesday November 02, 2010 @07:37AM (#1860000)
That kind of should be the first train of thought in python too, why using "+" to add strings!? it maybe fixed in py3k but its still not worth it in py2.X

<pre> return ''.join(map(chr, list)) </pre>

Also the liberal use of the words list and string bothers me.

Re:Python Patterns - An Optimization Anecdote by dish on Tuesday November 02, 2010 @06:36PM (#1862722)
Since Guido invented the words "list" and "string" in python at least, I guess him using them doesn't bother me.