My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.
Showing posts with label Code. Show all posts
Showing posts with label Code. Show all posts

Sunday, May 22, 2011

size maniacs or just twitterable examples ?

maybe both, but I like the idea!
Many times I have added something like #tweetcode at the end of a tweet created with the single goal to be small enough for ... well, a tweet!
@jedschmidt bought a spanish domain called 140byt.es based over github forks in order to provide all sort of tweets that may solve a specific problem in an efficient way: it kinda work on copy and paste!
Kinda ... because rules may not truly work stand alone and snippets are suggested without a "tooltip" example, at least in the main page.

What Can We Do In 140 Bytes ?

  • tweet a solution for a simple task
  • provide an idea about how to solve a task
  • solve a task in a truly efficient way
Yeah, some snippet is absolutely everything we may need to solve a problem.
The most simple example is the hex2rgb and rgb2hex, a problem that could be solved easily via bitwise operators and a tiny bit of math.

How Can 140 Bytes Be Enough ?

Using few tricks suggested in this page we can realize it is possible to shrink the code that badly to obtain a decent copy and paste tweet.

How Can We Contribute ?

Fork it and push it with some example. I have done the mistake posting a "117 bytes to bind" that follows jed logic but it is not forked yet.

function(a,b,c){b=[].slice.call(arguments,1);c=this;return function(){return a.apply(c,b.concat.apply(b,arguments))}}

Well, I'll do better next time while you can have fun and check examples right now ;)


Update
DAMN IT! Jed shrinked another byte!
function(a,b,c){b=[c=this].slice.call(arguments,1);return function(){return a.apply(c,b.concat.apply(b,arguments))}}

Tuesday, February 16, 2010

JSLint: The Bad Part

Every programming language has somehow defined its own standard to write code. To be honest, as long as code is readable, clear, and indented when and if necessary, I think we do not need so many "code style guides" and, even worst, sometimes these "code standards" let us learn less about the programming language itself, helping if we are beginners, sometimes simply annoying if we are professionals.

Disclaimer

This post aim is absolutely not the one to blame one of my favorite JS gurus, this post is to inform developers about more possibilities against imperfect automation we'll probably always find in whatever excellent spec we are dealing with. This post is about flexibility and nothing else!

JSLint And Code Quality

Wehn Mr D says something, Mr D is 99.9% right about what he is saying ... he clearly represents what we can define a Guru without maybe or perhaps but he, as everybody else here, is still a programmer, and we all know that every programmer has its own style if we go down into details.
Mr D programming style has been historically summarized in this Code Conventions for the JavaScript Programming Language page.
All those practices are basically what we can find out about our code using a well known and widely adopted parser: JSLint, The JavaScript Code Quality Tool.
I write JavaScript and ActionScript (based over the same standard) since about 2001 and generally speaking, as experienced developer, I trust what I meant to do, and rarely what an automation tool supposes to teach me about the language.
This is like studying remembering rules rather than being able to understand them, something surely academical, nothing able to let us explore and discover new or better solutions ... we are stuck in those rules, but are we machines? Are we Mr D code style clones?
This post is about few inconsistent points regarding JavaScript Code Quality, with all due respect for somebody that simply tried to give us hints!

Indentation

The unit of indentation is four spaces. Use of tabs should be avoided because there still is not a standard for the placement of tabstops
While size always matters, since to move 1Gb or 600Mb in a network still makes a big difference, I wonder what's wrong with just two spaces. The monospace font we all use to write code on daily basis is "large enough", and while 2 spaces rather than 4 are extremely easy to spot, 4 spaces are absolutely ambiguous.
How many times we had to check via cursor if some other editor placed a tab rather than 4 spaces there? Ambiguity is something that does not match at all with the concept of Code Quality, am I wrong?
Finally, while everybody in this world has always used innerHTML due its better performances against the DOM, Mr D. tells us that tabs are not defined as a standard ... have we never heard something like de facto standard?
Specially in a unicode based language as JavaScript is, where tabs are indeed replaced by "\t" even in Mr D JSON specs, how can we think about whatever JavaScript IDE or Engine unable to understand tabs? Let's avoid them, but still, at least let's replace them with something that does NOT occupy exactly the same space!

Variable Declarations

All variables should be declared before used. JavaScript does not require this, but doing so makes the program easier to read and makes it easier to detect undeclared variables that may become implied globals.
OK, got the point, minifier or munger will take care about this so it could make sense. Now, everything is fine to me, as long as I don't read the next immediate point:
The var statements should be the first statements in the function body.
... are we serious here?
So, if var declaration is the first thing I should do, why on earth I should spend 10 times my time to write semiclons and var again?

// first thing to do
var a = 1;
var b = 2;
var c = 3;
var d = {};

// AGAINST
var a = 1, b = 2, c = 3,
d = {}
;

Faster to type, easier to read, I can even group blocks of variable declaration to define different types (primitive first, object after, undefined later if necessary) and thanks to indentation, the precedent point, I must be an idiot to do not understand what the hell I wrote. Is it just me?
I prefer to perfectly know the difference between comma and semicolon and these two buttons are in a different place, there is NO WAY I coul dmake a mistake unless I don't know the difference ... but in that case I guess we have another problem, I know nothing about JS!
Furthermore, something kinda hilarious to me:
Implied global variables should never be used.
OK, assuming for whatever reason we don't consider global functions references/variables, we should forget:
  • undefined
  • window
  • navigator
  • document
  • Math
  • jQuery (dollar $ is global baby!)
  • everything else that supposed to be reached on the global scope
I may have misunderstood this point so I do hope for some clarification, but again, the difference between a local scoped variable and a global one should be clear to everybody since JSLint cannot solve anything, and I'll show you later.

Function Declarations

I agree lmost everything about this chapter, but there are surely a couple of inconsistencies here as well.
There should be no space between the name of a function and the ( (left parenthesis) of its parameter list. There should be one space between the ) (right parenthesis) and the { (left curly brace) that begins the statement body.
...
If a function literal is anonymous, there should be one space between the word function and the ( (left parenthesis). If the space is omited, then it can appear that the function's name is function, which is an incorrect reading.
Let me guess: if there is a name, there must be a space to identify the name, if there is no name, the must a space as well? A function called function which is a reserved word?
I am sure Mr D has much more experience than me, but I wonder if that guy that wrote function function() {} has been fired, is in the Daily WTF website, it is part of the shenanigans group, or if it is still working beside Mr D ... in few words, how can be no space and a bracket ambiguous?

var f = function(){};
I want to honestly know who is that programmer able to confuse above code ... please write a comment with your name and your company, I will send you a Congratulation You Are Doing Wrong card ... I'll pay for it!!!
Same is for the space after the right parenthesis, as if an argument could accept brackets so that we could be confused about the beginning of the function body, isn't it?
Some bad code there in this chapter as well, which let me think truly weird stuff:

walkTheDOM(document.body, function (node) {
var a; // array of class names
var c = node.className; // the node's classname
var i; // loop counter results.
if (c) {
a = c.split(' ');
for (i = 0; i < a.length; i += 1) {
...

So we have to declare every variable at the beginning, included variable used for loops, the i, so the day engines will implement a let statement we'll have to rewrite the whole application?

var collection = (function () {
var keys = [], values = [];

return {
....

wait a second, consistency anybody? How come the next paragraph uses a natural assignment as that one while the Code Quality is to do not use it?

Names

Names should be formed from the 26 upper and lower case letters (A .. Z, a .. z), the 10 digits (0 .. 9), and _ (underbar). Avoid use of international characters because they may not read well or be understood everywhere. Do not use $ (dollar sign) or \ (backslash) in names.
I am not sure if Prototype and jQuery guys shouted something like: epic fail but I kinda laughed when I read it. It must be said that these practices are older than recent framework, and this is why I have talked about do not explore code potentials at the beginning of this post.
Do not use _ (underbar) as the first character of a name. It is sometimes used to indicate privacy, but it does not actually provide privacy. If privacy is important, use the forms that provide private members. Avoid conventions that demonstrate a lack of competence.
So if I got it right, if we identify private variables inside a closure, where these variable actualy are private, we should not identify them as private so we can mess up with arguments, local public variables (remember cached vars?) and everything else ... ambiguous!

Statements

Labels
Statement labels are optional. Only these statements should be labeled: while, do, for, switch.
...
continue Statement
Avoid use of the continue statement. It tends to obscure the control flow of the function.

Labels are fine, continue, which is basically an implicit label similar to goto: nextloopstep should be avoided. But as far as I read the return statement able to break whatever function in whatever point has no hints about being only at the end of the function bosy as is for ANSI-C programmers?

Block Scope

In JavaScript blocks do not have scope. Only functions have scope. Do not use blocks except as required by the compound statements.

with (document) {
body.innerHTML = "is this a scope?";
}
Never mind, somebody in ES5 strict specs decided that with statement is dangerous ...

=== and !== Operators.

It is almost always better to use the === and !== operators. The == and != operators do type coercion. In particular, do not use == to compare against falsy values.
This is the most annoying point ever. As a JavaScript developer, I suppose to perfectly know the difference between == and ===. It's like asking PHP or Ruby people to avoid usage of single quoted strings because double quoted are all they need ... does it make any sense?

// thanks lord null is falsy as undefined is
null == undefined; // true
null == false; // false
null == 0; // false
null == ""; // false
null == []; // false
null === null; // true, this is not NaN

In few words, as I have said already before, null is == only with null and undefined, which means we can avoid completely redundant code such:

// Mr D way
if (v !== null && v !== undefined) {
// v is not null neither undefined
}

// thanks JavaScript
if (v != null) {
// v is not null neither undefined
}

Moreover, since undefined is a variable it can be redefined somewhere else so that the second check could easily fail ... and where is security in this case?

// somewhere else ..
undefined = {what:ever};


// Mr D way
if (v !== null && v !== undefined) {
// this is never gonna happen AS EXPECTED
}

Please Mr D whatever you think about this post, think more about that silly warning in JSLint: it's TOO ANNOYING!!!
One last example about ==, the only way to implicitly call a valueOf if redefined:

if ({valueOf: function(){return !this.falsy;}} == true) {
// hooray, we have more power to deal with!
}


eval is Evil

The eval function is the most misused feature of JavaScript. Avoid it.
eval has aliases. Do not use the Function constructor. Do not pass strings to setTimeout or setInterval.

aliases? It seems to me that eval is misunderstood as well since there is no alias fr eval. This function may be evil specially because it is able to bring the current scope inside the evaluated string.
Function and setWhaatever do not suffer this problem, these global function always ignore external scope.
Moreover, it is thanks to Function that we can create ad-hoc, runtime, extremely performer functions thanks to dynamic access to static resolution:

function createKickAssPerformancesCallback(objname, case, stuff, other) {
return Function(objname, "return " + [objname, case, stuff, other].join("."));
}

Where exactly is the eval here and why we should avoid such powerful feature when we are doing everything correct?

Unit Test IS The Solution

If we think we are safe because of JSLint we are wrong. If we think we cannot do mistakes because of JSLint we are again wrong. JSLint could help, as long as we understand every single warning or error and we are able to ignore them, otherwise it won't make our code any better, neither more performance killer, surely not safe.
There are so many checks in JSLint that somebody could simply rely in this tool and nothing else and this, for the last time, is wrong!
Next part of the post is about a couple of examples, please feel free to ask more or comment if something is not clear, thanks.

JSLint: The Bad Part

All these tests are about possibly correct warnings, often useless on daily basis code. Please note all codes have been tested via The Good Parts options and without them.

Conditional Expressions

I twitted few days ago about this gotcha. An expression to me does not necessary require brackets, specially it does not require brackets when it is already inside brackets.

"use strict";
var lastValidArgument;
function A(b) {
// I mean it!!!
if (lastValidArgument = b) {
return "OK";
}
}

Somebody told me that if we put extra brackets, as JSLint suggests, it measn that we meant that assignment, rather than a possible missed equal.
First of all, if == is discouraged in favor of === how can be possible developer forgot to press the bloody equal sign three times? It does not matter, the inconsistency here is that if I properly compare there two variables leaving there brackets, theoretically there to let me understand I am doing an assignment rather than comparing vars, nothing happens:

"use strict";
var lastValidArgument;
function A(b) {
if ((lastValidArgument === b)) {
return "OK";
}
}

I would have expected a warning such: Doode, what the hell are you doing here? You have superflous brackets around! ... nothing, inconsistent in both cases, imho.

Unused variable

A proper syntax analyzer is truly able to understand if inside a whole scope, we used a variable as we meant to do. Unfortunately, here we have a totally useless warning/error about an extremely silly, but possible, operation. To avoid the error:

"use strict";
(function () {
var u;
// we forgot to assign the "u" var
// how can this if remove such error from this scope?
if (u) {
}
}());

Agreed, u has been used, but why on earth I have no warnings about a completely pointless if? As far as I understand, variables are truly well monitored ... this requires an improvement ... or remove the Unused variable check since in this case it does not change anything.

Pattern to avoid global scope pollution

The new operator is powerful, but it could be omitted and JSLint knows this pretty well! We, as developers, are able to modify behaviors, using functions duality to understand what's going on. Example:

"use strict";
function A() {
if (!(this instanceof A)) {
return new A();
}
}

// always true
A() instanceof A;
new A() instanceof A;

Cool, isn't it?
Problem at line 7 character 9: Missing 'new' prefix when invoking a constructor.
How nice, thanks JSLint!

Look behind without look forward

More about new, who said this requires parenthesis? As soon as I write new I am obviously trying to create an instance. Since the constructor will be exactely the one referenced after, and since after this operation there will be a semicolon, a comma, a bracket (return without semicolon), how can it be possibly a problem for JavaScript?

var a = new A;

If I don't need arguments, I feel kinda an idiot to specify parenthesis ... maybe it's just my PHP background, isn't it?

class A {}
$a = new A; // OK
$b = 'A';
$a = new $b; // still ok
$a = new $b(); // WTF, $b is a string

// oh wait ...
$b = 'str_repeat';
$b('right', 2); // rightright


Strictly Compared

I have already talked about null and == feature, now let's see how dangerous can be JSLint sugestion:

"use strict";
function pow(num, radix) {
return Math.pow(num, radix === null || radix === undefined ? 2 : radix);
}

// somewhere else, since not only eval is evil
[].sort.call(null)["undefined"] = 123;

Above code will both pass JSLint and always fail the check || radix === undefined since undefined will be 123 primitive.
You know what this mean? Unless we do not define an undefined local scope variable for each function (the most boring coding style ever, imho) we should simply avoid === undefined checks, these are both unsafe, these slow down code execution since undefined is global and requires scope resolution, and these are a waste of bytes

function pow(num, radix) {
return Math.pow(num, radix == null ? 2 : radix);
}

That's it, there is no value that could mess up that check: undefined, null, or a number, 0 included!

Nothing bad in this code

This is the best way I know to create a singleton, or a prototype, to have a private scope as well, shadowing the runtime constructor:

"use strict";
var Singleton = new function () {
// private function (or method)
function _setValue(value) {
// lots of stuff here
_value = value;
}
var _value;
this.get = function () {
return _value;
};
this.set = function (value) {
if (!_value) {
_setValue(value);
}
};
this.constructor = Object;
};

Here we have a Jackpot:
Error:
Problem at line 4 character 14: Unexpected dangling '_' in '_setValue'.
Problem at line 6 character 9: Unexpected dangling '_' in '_value'.
Problem at line 6 character 9: '_value' is not defined.
Problem at line 8 character 9: Unexpected dangling '_' in '_value'.
Problem at line 10 character 16: Unexpected dangling '_' in '_value'.
Problem at line 13 character 14: Unexpected dangling '_' in '_value'.
Problem at line 14 character 13: Unexpected dangling '_' in '_setValue'.
Problem at line 2 character 17: Weird construction. Delete 'new'.
Problem at line 18 character 2: Missing '()' invoking a constructor.

We can nullify the Singleton variable itself, but still nobody else can have access to that scope. This is what I call a variable or method private, and I mean it!
Underscore is perfect as first character, since it helps us to understand a "protected method/property", which is never truly protected, and a real private method/property, shared across instances if it's a variable, usable as private method if called via a public one.
The best one ever, in any ase is:Weird construction. Delete 'new'. ... Weird what? A lambda based language cannot create runtime via lambdas instances?

Conclusion

I hope this post will help both Mr D. and developers, the first guru to improve JSLint syntax checks, while latter people to understand errors, being able sometimes to completely ignore them.
I am looking forward for some feedback or, even better, something I did not consider or some example able to demonstrate or underline my points, thanks for reading.

Monday, August 17, 2009

Konami Code as DOM Event

If You do not know what is the Konami Code you are too young, or not geek at all.
In both cases, it does not matter, nobody is perfect, but what we should know is that some truly affectionate developer though to put this code to enable secret user powers, even if the the software is, as example, extremely recent.

So why not? Why can't we all have our secret mode in the most popular platform as the World Wide Web is?

Konami Code Event



var onkonamicode = function(el, fn){
// The Super Code Event by WebReflection - Mit Style
function onkonamicode(e){
konamicode.push((e || event).keyCode || e.charCode);
if(
konamicode.length === 10 &&
konamicode.join(".") === "38.38.40.40.37.39.37.39.66.65"
){
if(el.removeEventListener)
el.removeEventListener("keydown", onkonamicode, false);
else
el.detachEvent("onkeydown", onkonamicode);
fn(e);
};
clearTimeout(i);
i = setTimeout(clear, 1000);
};
function clear(){
konamicode = [];
};
var konamicode = [], i = 0;
if(el.addEventListener)
el.addEventListener("keydown", onkonamicode, false);
else
el.attachEvent("onkeydown", onkonamicode);
};


How To Activate Konami Code


It is that simple:

onkonamicode(document, function(e){
alert("access guaranteed");
});

Now try to perform the magic sequence and that's it, you have extra power!

Sunday, August 02, 2009

PyramiDOM - from Alpha to Beta

As promised, I have commented and improved my last experiment: PyramiDOM, (IE version) now with some new feature:

  • One click from bookmark to add PyramiDOM, another one to remove it

  • In a single session, colors are preserved even if PyramiDOM is added and removed more than once

  • Good browsers with W3C DOM events support and/or a console, will experience a better PyramiDOM thanks to automatic update feature and related dom nodes logged in the console

  • last part of the bookmark is the size of each brick. Right now it is 2 but you can easily change it to 4, 6, 8, whatever multiple of 2 you prefer



The PyramiDOM Source Code


It is really simple and the main logic is behind the Brick constructor and every brick instance.

(function(size){

var // shortcut to attach/detach events
add = document.addEventListener ?
function(node, name, callback){
node.addEventListener(name, callback, false);
}:
function(node, name, callback){
node.attachEvent("on" + name, callback);
}
,
del = document.removeEventListener ?
function(node, name, callback){
node.removeEventListener(name, callback, false);
}:
function(node, name, callback){
node.detachEvent("on" + name, callback);
}
,
// scope shortcut for document.body
body = document.body,
// scope shortcut for parseInt
i = parseInt,
// render timeout varible
t = 0,
// events filter (enable/disable)
exec = true,
// internal shortcuts
node, style
;

// main function, just a loop over each node to create a new Brick stack
function PyramiDOM(/* Brick */ parent, /* HTMLElement */ dom){
for(var child, node, childNodes = dom.childNodes, i = 0, length = childNodes.length; i < length; ++i){
if((node = childNodes[i]).nodeType === 1)
parent.add(PyramiDOM(new Brick(node, parent), node));
};
return parent;
};

// via brick info create a link (for alt/title easy tooltip)
// and append into the dom node
PyramiDOM.render = function render(/* Brick */ parent, /* HTMLElement */ dom){
var a = document.createElement("a"),
style = a.style,
alt = parent.dom.nodeName
;
if(parent.dom.id)
alt += " #" + parent.dom.id;
if(parent.dom.className)
alt += " " + parent.dom.className;

// the id contains this indexOf related brick in the Brick.register stack
a.id = parent.id + "-pyramidom";
// using parseInt will guarantee a quick integer transformation

a.title = a.alt = alt;
style.position = "absolute";
style.margin = style.padding = 0;
style.top = parent.top + "px";
style.left = parent.left + "px";
style.height = parent.height + "px";
style.width = parent.width + "px";
style.background = parent.color;
dom.appendChild(a);
// recursion: for each brick children render a link
for(var children = parent.children, i = 0, length = children.length; i < length; ++i)
render(children[i], dom);
};

// check if the node was already there
// in order to be able to remove PyramiDOM with another click
// in the bookmark menu
PyramiDOM.node = document.getElementById("pyramidom");

// if present (re-clicked) ...
if(node = PyramiDOM.node){
// ... remove node
del(document, "DOMNodeInserted", document.PyramiDOM);
del(document, "DOMNodeRemoved", document.PyramiDOM);
body.removeChild(node);
node.innerHTML = "";
PyramiDOM.node = node = null;
return;
} else {
// create the node
node = PyramiDOM.node = body.appendChild(document.createElement("div"));
style = node.style;
node.id = "pyramidom";
style.top = "0px";
style.left = "0px";
style.position = "absolute";
style.zIndex = 2147483647;
// attach events
add(node, "mousedown", function(e){
var target = (e || event).target;
if(target.nodeName === "A"){
// try to show the related node in the console
try{console.log(Brick.register[i(target.id)].dom)}catch(e){};
}
});
add(node, "mouseover", function(e){
var target = (e || event).target;
if(target.nodeName === "A"){
target = Brick.register[i(target.id)];
if(target.dom.style){
target.background = target.dom.style.background || "";
target.dom.style.background = "yellow";
}
}
});
add(node, "mouseout", function(e){
var target = (e || event).target;
if(target.nodeName === "A"){
target = Brick.register[i(target.id)];
if(target.dom.style)
target.dom.style.background = target.background;
}
});
add(document, "DOMNodeInserted", document.PyramiDOM = function(){
// if modification is NOT PyramiDOM itself
if(exec){
// avoid greedy computations
if(0 < t)
clearTimeout(t);
// be sure last timeout will represent the current DOM
t = setTimeout(function(){
// disable insert/remove events
exec = false;
body.removeChild(node);
PyramiDOM.render(PyramiDOM(new Brick(document), document), node);
body.appendChild(node);
// enable insert/remove events
exec = true;
}, 250);
};
});
add(document, "DOMNodeRemoved", document.PyramiDOM);
};

// each brick is an instance with some computated property
function Brick(dom, parent){
this.dom = dom;
// register this instance (reference via link id)
this.id = Brick.register.push(this) - 1;
// set color via nodeName
this.color = Brick.color(dom.nodeName);
// level means how nested is related dom element
this.level = (this.parent = parent) ? parent.level + 1 : 0;
// calculate the left position of this brick
this.left = this.level * this.width;
// set an empty children stack
this.children = [];
// if this is not the root
if(this.level){
// if the parent has other children
if(parent.children.length){
// get latest child position via top, height, plus 1 pixel as space
var child = parent.children[parent.children.length - 1];
this.top = child.top + child.height + 1;
} else
// this brick is the first for this level
// let's put it a bit more down than its parent
// to obtain the Pyramid effect
this.top = parent.top + (this.width / 2) << 0;
} else
// root, top is 0
this.top = 0;
};

// generate random unique colors based on a generic string, nodeName in this case
// the reason it is cached is to avoid epileptic effect each time the pyramid
// is regenerated (new in this beta version)
Brick.color = document.PyramiDOMColor || (document.PyramiDOMColor = (function(){
function color(hex){return new Array(7 - hex.length).join("0") + hex};
function random(nodeName){
// quickly avoid duplicated
do{var c = (Math.random()*0x1000000)<<0}while(cache[c]);
cache[c] = true;
// cache result to avoid this operation for same nodeName
return hash[nodeName] = "#" + color(c.toString(16));
};
var cache = {}, hash = {};
return function(nodeName){return hash[nodeName] || random(nodeName)};
})());

// every brick object is registered in a global public stack
Brick.register = [];

// every brick has a default size
Brick.prototype.width =
Brick.prototype.height = size;

// every brick has a children stack
Brick.prototype.add = function(child){
this.children.push(child);
this.height += child.height + 1;
};

// create PyramiDOM
document.PyramiDOM();

// size of each brick (2, 4, 6 up to whatever % 2 === 0)
})(2);


Have fun with PyramiDOM :)

Saturday, February 21, 2009

On My Vicious JavaScript Code

Disclaimer

This post is a reply to kangax question:I’m sorry but why such vicious coding style?
I'd like to explain my point of view about JavaScript code style so, if interested, please read until the end, thank you :)



Some Background

I study and use JavaScript since year 2000 and one of the most interesting thing about this language is that even if it is "that old" you never stop to learn something new (techniques, strategies, adapted patterns, etc).
At the same time, the "biggest trouble" of this language is its weight in a page, which is the reason we all use minified and gzipped or packed versions of our application. Coming from a "33Kb modem internet era" I always tried to pay attention about the size and I studied and created both a JavaScript minifier and a compressor.



Compressors Rules

Unless we are not using an "incremental" compressor, as GIF is, we should consider that packer algorithm, as gzip and deflate, are dictionary based compressors (Huffman coding).
These techniques to minimize our scripts size give us best compression ratio if we use a reduced dictionary. In few words, if we have these two piece of codes:

// code A
function tS(obj){
return obj.toString();
};

// code B
function toString(obj){
return obj.toString();
};

even if the length of the code A is smaller, it will use 1 or more bytes than code B once compressed.
The reason is really simple. Try to imagine that both codes are converted in this way:

// code A
0 1(2){3 2.4();};[function,tS,obj,return,toString]

// code B
0 1(2){3 2.1();};[function,toString,obj,return]

Code B has a reduced dictionary, and reduced dictionary means best ratio. That's why when I introduced years ago the little bytefx library I defined it "packer friendly" (variables name are similar in the entire code).



How Compressors Changed My Way To Code in JavaScript

Accordingly, and probably against every common programming naming convention practice, those studies let me think that as long as a variable name is meaningful enough, it does not matter if it is perfectly clear to recognize or not, since in every case when we want to understand a code, we need to read it from the beginning to the end. Here there are a couple of example:

// (pseudo)compilable language practices
var splitted = "a.b.c".split(".");
function argsToArray(args){
return Array.prototype.slice.call(args);
};

// my code style
var split = "a.b.c".split(".");
function slice(arguments){
return Array.prototype.slice.call(arguments);
};

The split variable is meaningful enough, it is something that has been splitted via split method, and the same is for the slice function: I use it to call the slice Array method over a generic ArrayLike object, as the Object arguments is.



Confusion, Ambiguity, WTF About arguments? Not Really!


The reason I chose inside the slice function the variable name arguments is simple: in that function I do not need its own ArrayObject arguments, while I will use that function mainly with an ArrayObject arguments variable from other functions.

function doStuff(){
var Array = slice(arguments); // other stuff
};

How can be then that arguments variable considered ambiguous?
Moreover, that function "will cost zero once compressed", because in every code I've seen so far the generic function arguments variable, plus the slice method from Array's prototype, are always part of the rest of the code. So, in terms of bytes, I have added a useful function in only 8 extra bytes: (){();};



OMG! I even called a variable Array inside the doStuff function!!!


Yes I did indeed, and the reason is still the same: almost every library or piece of code use the Array keyword but if I do not need the global Array constructor in that scope, why should I leave such meaningful dictionary word untouched?
Moreover, the Array global constructor is used mainly because of its prototype, but once I have an Array variable called Array I can simply use directly its methods instead of the global one, considering those are exactly the same.

function doStuff(){
var Array = slice(arguments);
Array.push.apply(this, Array);
return this
};

Finally, the day we will need the native global constructor, String, Object, Array, Function, we can always use the safe window.Array or, if we decided to name a variable window inside a scope, the self.Array or the this.Array or the in line global scope resolution call:

var toString = function(){return this.Object.prototype.toString}();




Is It Just About Naming Convention?

I use different strategies to be sure my code will be the smallest possible. As example, and as showed above on toString assignment, if I need a runtime called function which returns a value and it is not that big function, I do not use parenthesis around.
If an assignment or a return is before an end bracket "}" I do nt usually put the semi colon at the end. For the interpreter, it does not matter, because it transform in its own way the function.

alert(function(){return this.Object.prototype.toString});

// produced output
function(){
return this.Object.prototype.toString;
}
// indentation, plus semicolons where necessary

The rest is usually managed by the minifier, so the fact that a return"a" does not need a space between return and the String "a" is superfluous if we use, for example, a clever minifier as the YUI Compressor is. The same is for loop with a single line to execute, I do not use brackets (I love Python indentation style).
for(var key in obj)
if(typeof obj[key] == "string")
obj[key] = parse(obj[key]);




My Style Cons


  • tools like JSLint often fail to recognize my code as valid so I do not use JSLint (... but fortunately I do not need it, I now my code is beautiful :P)

  • in a Team we should all respect Team code conventions, so my code style could not be the best choice if other programmers do not know JavaScript that much and/or use a specific/different code style

  • if the development product will not use minifier + compressors my code style could produce bigger size instead of smaller (Object instead of obj or o)

  • my code could require a better lecture than a quick one, but this is true for every library if we would like to understand properly a trick, the entire scope, an assignment, etc, etc ...





My Style Pros


  • final size, minified and packed/gzipped, is most of the case reduced if compared with other "code scripters"

  • more big is the library I would like to extend, less my implementation costs, thanks to a wide range of words to use (common like key, Object, arguments, Function, etc plus others)

  • variable names are often more meaningful than other and instead of function(str, callback, obj){} I bet we cannot understand variables type with a function like function(String, Function, Object){}. So, if possible and when necessary, my code style is closer to strict programming language than every other, allowing me to save time writing directly String as variable name, instead of /* String */ str





Conclusion

I know for somebody my vicious style could be considered a non-sense or something too "extreme" or hard to maintain. But, on the other hand, I am not developing public libraries (I prefer to extend them rather than reinvent the wheel if it is not necesary at all) and my implementations, for me, are much more easy to understand/maintain than others since I often perform linear (sometime tricky) operations which make absolutely sense to me and in a single line when it is possible. You like it? You don't? It does not matter, at least now you know how much pervert a programmer mind could be for an "out of the common rules language" as JavaScript is.
Enjoy my craziness :D

Update
Since telling you I have studied these cases was not enough, here is a truly simple demonstration for the Anonymous user that left the comment:

<?php
$output = array();
for($i = 0; $i < 80; $i++)
$output[] = 'testMe';
$str = implode('.', $output);
echo 'WebReflection: '.strlen(gzcompress($str, 9)); // 21
echo '
';
$output = array();
for($i = 0; $i < 80; $i++)
$output[] = 'test'.str_pad($i + 1, 2, '0', STR_PAD_LEFT);
$str = implode('.', $output);
echo 'Anonymous: '.strlen(gzcompress($str, 9)); // 144
?>

21 bytes against 144 so please, if you think my point is wrong, demonstrate it :)

Sunday, July 27, 2008

Google Code Jam: Mousetrap in 4 languages - GAME OVER

First of all, I would like to thank the Google team for Code Jam opportunity, and its organization: AMAZING!

Yesterday I have lost my Round without a single commit.
This time I have not excuses, it was simply my fault.
I did not understand properly first two problems, or better, expected results, but I was sure the reason was my poor English knowledge, and I wouldn't be silly, asking silly questions (some question was silly enough, so, next time, I'll be less shy than this time).

Accordingly, since Code Jam is a challenge, I chose to solve the most difficult problem, the Mousetrap. First of all, because the problem, and the expected result, was so simple to understand, secondly, because it was the best one for points :geek:

Problem Analysis


Ok, we had 2 hours to analyse the problem, to find the best solution, and to commit results, and this time I did not even download the test, because I would like to be sure that my solution was good enough to solve the problem.

Count positions ... no, don't do it, count movements, no, do not count at all!


My first 3 versions of Mousetrap were so tricky, that no one worked as expected :D
After about one hour trying to find the perfect algorithm to know where each card has to be during the game, I realized that I was trying to solve them in a complex way (a sort of home made equation), and without results, instead of simply think exactly what was going on in the deck during the game.
Anyway, I wasn't able to finish the code, specially because my "perfect solution" was trying to destroy my CPU! So, honestly, for my brain and my knowledge, time was not enough to complete that task.

Brainstorming


My approach was simple: create the perfect deck!
Once we have a perfect deck, find positions is something extremely simple, since each number is, at the begin, a deck index itself minus 1 (i.e. 1,2,3,4,5 as indexes: 0,1,2,3,4), so once you have moved each card over indexes, you can find card positions simply using created array.

card = "5"
result[(int)card - 1] = ... moved card.

At this point, we need to create the deck, and nothing else.
The first version was based on movements, and removed cards, to know the position of each card in that index. A sort of tracing, using a simple function like this one:

function movements(card){
return 0 < card ? card + movements(card - 1) : 0;
}

In this way we can know that when we are looking for card N, we have removed N-1 cards beforfe, and moved movments(N-1) time other cards.
This was probably the right direction, but it was exponential, and results completely wrong ... and snce we had 2 hours, I though to change strategy.

The most simple, logical, and expensive solution at all


Try to imagine we have 5 cards, so the deck will be: 1,2,3,4,5
The sequence, during the game, will be this one:

12345 [card = 1, pos 1]
2345 // remove one, and count fr next card
3452 [card = 2, pos 3]
452 // remove one, and count for next card
524 // counting ...
245 [card = 3, pos 2]
45 // remove one ...
54 // counting ...
45 // counting ...
54 [card = 4, pos 5]
4 // counting ...
4 // counting ...
4 // counting ...
4 // counting ...
4 [card = 5, pos 4]

Above operation is exponential as well, but in my mind it was the best one ever to be sure about the result. That is why I started to play the game!

Mousetrap with JavaScript


When I realized that in that simple way the code was truly slim, I though about 2 possibilities: 1 - I am a f#*@in genius, 2 - There is something wrong, it cannot be that simple, I am an idiot!
Once I have created the code:

// JavaScript
function perfectDeck(cards){
for(var
deck = range(cards),
result = range(cards),
count = 0,
i = 0;
i < cards; i++
){
while(count++ !== i)
deck.push(deck.shift()); // move cards
result[deck.shift()] = count;// remove one
count = 0; // start counter again
};
return result;
};

// JavaScript Extra
function range(length){ // return an array with 1:1 index/value integers
for(var i = 0, result = new Array(length); i < length; i++)
result[i] = i;
return result;
};

// example
alert(perfectDeck(5))
// 1,3,2,5,4

I did some test, and I checked results in my minds, and those were expected. Well done?

Mousetrap, PHP implementation


At this point, I need to parse the input file, and to produce an output file.
Since the code was extremely simple, I have though about PHP, to be able to read the input, and produce the output to upload.

function perfectDeck($cards){
for(
$deck = range(0, $cards - 1),
$result = range(0, $cards - 1),
$count = 0,
$i = 0;
$i < $cards; $i++
){
while($count++ !== $i)
array_push($deck, array_shift($deck));
$result[array_shift($deck)] = $count;
$count = 0;
}
return $result;
}

Damn it, literally 1 minute to create my PHP perfectDeck version.
Now, lets do some test to be sure everything is correct ... ok, that's correct.
At this time, I read the problem again, and I realized that I was debugging with 3, 4, 5 or 7 cards, thinking that a deck could not have more than 15 cards (poker addicted!) ... well, things are a bit different, since limits are clear, and we are talking about a maximum of 5000 cards, and for the small input!!! :o

Python version


Since trying to generate the perfect deck with PHP, and 2500 cards, was extremely slow, I though that I could try to use another language, maybe faster, thanks to Psyco module.

from psyco import full
full()

// Python
def perfectDeck(cards):
deck = range(cards)
result = range(cards)
count = 0
i = 0
while i < cards:
while count != i:
deck.append(deck[0])
deck = deck[1:]
count = count + 1
result[deck[0]] = count + 1
deck = deck[1:]
count = 0
i = i + 1
return result

Of course, in this case Psyco cannot help that much, since the most expensive operation is with the deck, and not with math.

Need for speed, C# Mousetrap


As last chance, and since the code was producing expected results, I though about fixed Arrays, without a single scriptish operation.
Instinctively, I opened my visual C# Express Edition, instead of Dev C++ to create a C version ... maybe because it's long time I am not using them, but anyway, I know that using fixed length arrays I should not have speed problems at all.

// C# with fixed lengths
static int[] perfectDeck(int cards){
int[] deck = range(cards),
result = range(cards);
for(int i = 0, count = 0; i < cards; i++){
while (count++ != i)
move(ref deck);
result[deck[0]] = count;
deck = shift(deck);
count = 0;
}
return result;
}

// C# with fixed lengths - Extra
static int[] range(int Length){
int[] result = new int[Length];
for (int i = 0; i < Length; i++)
result[i] = i;
return result;
}

static int[] shift(int[] deck){
int i = 0,
Length = deck.Length - 1;
int[] result = new int[Length];
for (; i < Length; i++)
result[i] = deck[i + 1];
return result;
}

static void move(ref int[] deck){
int last = deck[0],
i = 1,
Length = deck.Length;
while (i < Length)
deck[i - 1] = deck[i++];
deck[i - 1] = last;
}


Good enough? NO WAY, speed is more close to Python than C, so I promised myself that next version of perfectDeck function will be written in C.
At the same time, it will never be enough fast, because big input as these limits:
T = 10, 1 ≤ K ≤ 1000000, 1 ≤ n ≤ 100, 1 ≤ di ≤ K

This means that my code will perform a factorial 1000000 changes, so honestly, the next step, will be to download some code from the competition, and learn which algorithm is the most clever and simple, to perform this task, in my mind, and in my implementation, completely mechanical.

Conclusion


I like challenges, and this one was amazing. I have learned at least these things yesterday, and I hope next year, I'll be more prepared:

  • Code Jam is fantastic!

  • Do not choose the most difficult task only to be in the top 100, but read in every case all of them before you start to write a single line of code

  • Do not use mechanical procedures, but think about efficient algorithms

  • Do not focus in a code, that for more than 2 times produced wrong results, or simply it is too slow, because it means there is something wrong in the logic, or in the algorithm

  • Go back to school, because even if you are a senior programmer, you do not work for the N.A.S.A. and you do not deal, daily, with algebra, math, geometry, and related stuff



If you are still reading, thank you too, I only would like to share my Google Code Experience, and my perfect costly nightmare Mousetrap solution.

Kind Regards

Thursday, July 17, 2008

Google Code Jam, or better, how to feel a 100% idiot !

Update 2


Congratulations! The results of the Google Code Jam 2008 Qualification Round are now official, and we're happy to announce that you have advanced to Round 1

Cheers :D
-----------------------------------------

Update


Guys, I do not know what Google judges will think about him/her, but in my mind, the qualification winner, for Python language, is the user camrdale, currently in position 40 of global score grid.

That code is extremely clear (come on, that is Python, how can be different!), essential, and the logic is probably not the perfect one, but is so linear that you can understand the problem even without reading them.

Well done camrdale, and good luck for the contest :geek:
-----------------------------------------

Guys, honestly, I did not think about that kind of selection only to participate, bloody hell!

First of All, the selection started at 11pm, and since I am an employee, and an hard worker as well, I though: who care? I have 24 hours to partecipate.

This is not true at all, I have discovered only after an entire day of work, programming in front at two monitors, drinking 3 red stuff and having 2 coffee, that the classification, or the total score, is based on both results, and when you commit your result.

But who had time to read the task before? Not me, honestly!

This simply means that USA, and vampires a part, nobody could stay in the top of that list.

I was so newbye in this contest, that the instant I went in the page, after login, I started to read the task, downloading automatically the first example file. no way, bad choice as first step, so first task failed because of time, well done!

After that, I chose the second task.
I truly feel like an idiot because I still have not understand at all what the hell is the correct check to avoid trains conflicts. But I hope i will discover soon them, because I am sure somebody more fresh than me understand perfectly the task, and properly solved them.

The last one is probably the most simple one, logically speaking, but at 10:30PM and after 14 hours spent in front of my PC, I really do not know who I am, how can I remember correct geometry permutations?

One think in my mind: I am an idiot!

So thank you for the opportunity Google team, I am sure next year I will ask a week of holidays to participate in another contest like that.

Kind Regards