My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Wednesday, October 12, 2011

What Is Wrong About 17259 Lines Of Code

Is the most popular, somehow pointless, and often funny gist of these days.

It's about Dart, the JavaScript alternative proposed by Google.

Why So Many Lines Of Code

The reason a simple "Hello World" contains such amount of code is because:
  1. the whole library core is included and not minified/optimized but on real world we should use the proper flag in order to generate files where only necessary parts of the library is included
  2. whoever created such core library did not think about optimizing his code
What am I saying, is that common techniques as code reusability do not seem to be in place at all:

// first 15 lines of Dart core
function native_ArrayFactory__new(typeToken, length) {
return RTT.setTypeInfo(
new Array(length),
Array.$lookupRTT(RTT.getTypeInfo(typeToken).typeArgs));
}

function native_ListFactory__new(typeToken, length) {
return RTT.setTypeInfo(
new Array(length),
Array.$lookupRTT(RTT.getTypeInfo(typeToken).typeArgs));
}

ListFactory is nothing, I repeat, nothing different from an Array and since the whole core is based on weird naming convention, nothing could have been wrong so far doing something like:

// dropped 4 lines of library core
var native_ListFactory__new = native_ArrayFactory__new;

Please note methods such Array.$lookupRTT and bear in mind that Dart does not work well together with JavaScript libraries since native constructors and their prototypes seem to be polluted in all possible ways.

Not Only Redundant Or Obtrusive Code

While I agree that at this stage can be premature to judge the quality of Dart code, once translated for JavaSript world, is really not the firt time I am not impressed about JavaScript code proposed by Google.
Google is a great company loads of ultra skilled Engineers. Unfortunately it looks like few of them have excellent JavaScript skills and most likely they were not involved into this Dart project ( I have been too hard here but I have never really seen gems in google JS libraries )

// line 56 of Dart core
function native_BoolImplementation_EQ(other) {
if (typeof other == 'boolean') {
return this == other;
} else if (other instanceof Boolean) {
// Must convert other to a primitive for value equality to work
return this == Boolean(other);
} else {
return false;
}
}

// how I would have written that
function native_BoolImplementation_EQ(other) {
return this == Boolean(other);
}

Please note that both fails somehow ..

native_BoolImplementation_EQ.call(true, new Boolean(false)) // true
// so that new Boolean(false) is EQ new Boolean(true)

... while if performances were the problem bear with me and look what Dart came up with ...

124 Lines Of Bindings

Line 80 starts with:

// Optimized versions of closure bindings.
// Name convention: $bind_(fn, this, scopes, args)

... and it cannot go further any different from what you would never expect ...

function $bind0_0(fn, thisObj) {
return function() {
return fn.call(thisObj);
}
}
function $bind0_1(fn, thisObj) {
return function(arg) {
return fn.call(thisObj, arg);
}
}
function $bind0_2(fn, thisObj) {
return function(arg1, arg2) {
return fn.call(thisObj, arg1, arg2);
}
}
function $bind0_3(fn, thisObj) {
return function(arg1, arg2, arg3) {
return fn.call(thisObj, arg1, arg2, arg3);
}
}
function $bind0_4(fn, thisObj) {
return function(arg1, arg2, arg3, arg4) {
return fn.call(thisObj, arg1, arg2, arg3, arg4);
}
}
function $bind0_5(fn, thisObj) {
return function(arg1, arg2, arg3, arg4, arg5) {
return fn.call(thisObj, arg1, arg2, arg3, arg4, arg5);
}
}

function $bind1_0(fn, thisObj, scope) {
return function() {
return fn.call(thisObj, scope);
}
}
function $bind1_1(fn, thisObj, scope) {
return function(arg) {
return fn.call(thisObj, scope, arg);
}
}
function $bind1_2(fn, thisObj, scope) {
return function(arg1, arg2) {
return fn.call(thisObj, scope, arg1, arg2);
}
}
function $bind1_3(fn, thisObj, scope) {
return function(arg1, arg2, arg3) {
return fn.call(thisObj, scope, arg1, arg2, arg3);
}
}
function $bind1_4(fn, thisObj, scope) {
return function(arg1, arg2, arg3, arg4) {
return fn.call(thisObj, scope, arg1, arg2, arg3, arg4);
}
}
function $bind1_5(fn, thisObj, scope) {
return function(arg1, arg2, arg3, arg4, arg5) {
return fn.call(thisObj, scope, arg1, arg2, arg3, arg4, arg5);
}
}

function $bind2_0(fn, thisObj, scope1, scope2) {
return function() {
return fn.call(thisObj, scope1, scope2);
}
}
function $bind2_1(fn, thisObj, scope1, scope2) {
return function(arg) {
return fn.call(thisObj, scope1, scope2, arg);
}
}
function $bind2_2(fn, thisObj, scope1, scope2) {
return function(arg1, arg2) {
return fn.call(thisObj, scope1, scope2, arg1, arg2);
}
}
function $bind2_3(fn, thisObj, scope1, scope2) {
return function(arg1, arg2, arg3) {
return fn.call(thisObj, scope1, scope2, arg1, arg2, arg3);
}
}
function $bind2_4(fn, thisObj, scope1, scope2) {
return function(arg1, arg2, arg3, arg4) {
return fn.call(thisObj, scope1, scope2, arg1, arg2, arg3, arg4);
}
}
function $bind2_5(fn, thisObj, scope1, scope2) {
return function(arg1, arg2, arg3, arg4, arg5) {
return fn.call(thisObj, scope1, scope2, arg1, arg2, arg3, arg4, arg5);
}
}

function $bind3_0(fn, thisObj, scope1, scope2, scope3) {
return function() {
return fn.call(thisObj, scope1, scope2, scope3);
}
}
function $bind3_1(fn, thisObj, scope1, scope2, scope3) {
return function(arg) {
return fn.call(thisObj, scope1, scope2, scope3, arg);
}
}
function $bind3_2(fn, thisObj, scope1, scope2, scope3) {
return function(arg1, arg2) {
return fn.call(thisObj, scope1, scope2, arg1, arg2);
}
}
function $bind3_3(fn, thisObj, scope1, scope2, scope3) {
return function(arg1, arg2, arg3) {
return fn.call(thisObj, scope1, scope2, scope3, arg1, arg2, arg3);
}
}
function $bind3_4(fn, thisObj, scope1, scope2, scope3) {
return function(arg1, arg2, arg3, arg4) {
return fn.call(thisObj, scope1, scope2, scope3, arg1, arg2, arg3, arg4);
}
}
function $bind3_5(fn, thisObj, scope1, scope2, scope3) {
return function(arg1, arg2, arg3, arg4, arg5) {
return fn.call(thisObj, scope1, scope2, scope3, arg1, arg2, arg3, arg4, arg5);
}
}

I really don't want to comment above code but here the thing:

Dear Google Engineers,
while I am pretty sure you all know the meaning of apply, I wonder if you truly needed to bring such amount of code with "optimization" in mind for a language translated into something that requires functions calls all over the place even to assign a single index to an array object

No fools guys, if you see functions like this:

function native_ObjectArray__indexAssignOperator(index, value) {
this[index] = value;
}

you may realize how much overhead exists in Dart once this is used in non Dart capable browsers.
These browsers will do, most likely, something like this:

try {
if (-1 < $inlineArrayIndexCheck(object, i)) {
native_ObjectArray__indexAssignOperator.call(object, i, value);
// or object.native_ObjectArray__indexAssignOperator(i, value)
}
} catch(e) {
if (native_ObjectArray_get$length.call(object) <= i) {
native_ObjectArray__setLength.call(object, i + 1);
}
try {
native_ObjectArray__indexAssignOperator.call(object, i, value);
} catch(e) {
// oh well ...
}
}

rather than:

object[i] = value;


Early Stage For Optimizations

This is a partial lie because premature or unnecessary optimizations are all over the place. 120 lines of binding for a core library that will be slower not only on startup but during the whole lifecycle of the program cannot solve really a thing, isn't it?

The Cost Of The Operator Overload

This is a cool feature representing other 150 lines of code so that something like this:

1 + 2; // 3

will execute most likely this:

// well not this one ...
function ADD$operator(val1, val2) {
return (typeof(val1) == 'number' && typeof(val2) == 'number')
? val1 + val2
: val1.ADD$operator(val2);
}

// but this
ADD$operator(1, 2); // 3

// with recursive calls to the function itself if ...
ADD$operator(new Number(1), new Number(2));

I am sure we all can sleep properly now that operators overload landed on the web, a feature that works nice with matrixes and vertexes as shortcut for multiplication is finally able to slow down every single addiction.
Did we really need this? Was operator overload the reason the web sucks as it is?
If so, I can't wait to see PHP moving into the same direction directly in core!

Which Problem Would Dart Solve

I am at line 397 out of 17259 and I cannot go further than this right now but I think I have seen enough.
I have heard/read about Dart aim which apparently is "to solve mobile browsers fragmentation".
Of course, mobile browsers, those already penalized by all possible non performances oriented practices, those browsers with the lower computation power ever, will basically die if there is no native Dart engine ... everything 2 up to 10 times slower for devices, specially older one, that will never see a native Dart engine in core and that for this reason will have to:
  • download the normal page ignoring the script application/dart
  • download via JavaScript the whole Dart transpiler
  • once loaded, grab all script nodes with type application/dart
  • translate each node into JavaScript through the transpiler
  • inject the Dart library core and inject every script
From the company that did not close the body tag in its primary page in order to have fastest startup/visualization ever, don't ya think above procedure is a bit too much for a poor Android 2.2 browser?
Bear in mind mobile browsers are already up to 100 times slower on daily web tasks than browsers present on Desktop.

Not Really What We Need Today

I keep fighting about what's truly needed on the web and I have said already surely not a new programming language ( and also ... guys you had already GWT, isn't it ? ).
I would enormously appreciate if anyone from Google will explain me why Dart was so needed and what kind of benefits can it bring today.
I can see a very long therm idea behind but still, why we all have to start from the scratch breaking everything we published and everything we know about web so far ?
Why this team of 10 or 30 developers did not help V8 one to bring StructType and ArrayType and boost up inferences in JavaScript ?
Why Dart ? What are the performances boost that V8 or WebCL will never achieve ? What is the WebCL status in Chromium ?
Where is a native CoffeeScript VM if syntax was the problem ?
... and many more questions ... thanks for your patience.

update ... I have to ask this too:
Doesn't this Dart language look like the VBScript of 2011 ?
Wasn't VBScript an Epic Fail ?