Saturday, May 24, 2008

More standard Stack, and more slim ArrayObject

I have just updated both Stack and ArrayObject constructors.

The Stack improvement is About concat method, now truly standard, accepting arguments that are not instance of Stack or Array.

var s = new Stack(1, 2, 3);
alert(s.concat([4, 5], 6)); // 1,2,3,4,5,6


Since this method uses defined slice one, there is no more reason to redefine concat method in inherited prototypes. That is why ArrayObject does not need anymore concat method, for a total of 4 fast redefined methods, plus inherited concat.

ArrayObject is now the fastest extended Array constructor that returns instances of the same constructor, ArrayObject.

ArrayObject is, at the same time, the base to create every other kind of cool library, using native Array methods power.

Enjoy!

Thursday, May 22, 2008

[OT] Does Zend rely in its own program language?

During an interesting meeting at work, me and my colleagues talked, for some reason, about Zend, and its weird market strategy.

What I mean, is that articles like this one, are daily present in our mind (we, as certified PHP developers :D)

At the same time, today I though about one simple thing:

  • Which program language is the diamond of MS? C#

  • Which program language does MS use to create applications? C#

  • Is MS IDE writen in C#, to develop in C#? Almost

  • Which program language is the diamond of Sun Microsystem? Java

  • Which program language does Sun use to create applications? Java

  • Is Eclipse IDE written in Java, to develop in Java? Almost



Same loop could be applied for Python, Ruby, D, Ocaml ... others, now stop one second ...

  • Which program language is the diamond of Zend? PHP

  • Which program language does Zend use to create applications? Java

  • Is Zend IDE written in PHP (GTK), to develop in PHP? NO



I know that phpgtk is a project out of the box, but it seems that Zend does not rely in its self proposed program language, or in its amazing extensions, as php gtk is.


  • Is it because PHP is not stable, scalable, powerful, as Java is? (don't you really know the answer?)

  • Is it because PHP is known as web purpose language, and it has not official support for desktop development? Maybe ... or maybe first point is more credible ...



I do like PHP, and what it offers daily for web development, but problems, bugs, simultaneous developed versions, let me think that probably we are using a program language, while its "official sponsor" does not like them that much ... but it's only my humble opinion, and I am using PHP since 1999 - am I an idiot?

Stack and ArrayObject - How to create an advanced subclassed Array constructor

Another problem left to solve is that after subclassing an Array one would like the return types of Array.prototype methods to be of the subclass type instead of its superclass type Array.

This comment is, basically, a summary of the reason I created the ArrayObject constructor.

Today, I have totally rewrote that constructor, using a Stack instance as prototype.

The Stack constructor aim is to subclass the Array one in the most compatible, and light, way.

For this reason, I have not changed native Array behaviours, those that return an Array, for example, instead of a Stack instance (concat, filter, map, slice).

But the good thing of Stack, is that now we can create our subclassed Array constructor, without affecting the native Array object, and adding, modifying, or removing, whatever we want.

For example, to solve the problem described on top of this post, I have simply modified inherited Stack methods, returning an instance of ArrayObject, every time we use, for example, a concat.

var a = new ArrayObject(1,2,3),
b = new ArrayObject(7,8,9),
c = a.concat([4,5,6], b);
alert(c); // 1,2,3,4,5,6,7,8,9
alert(c instanceof ArrayObject); // true

The same behaviour is obtained using slice, map, or filter, so we have our constructor, with our prototype, loads of possibilities.

The valueOf revenge


In ArrayObject, I have changed valueOf behaviour. This method returns basically the same information of toString, but it is used internally in a lot of cases.
One of them, is when you compare, sum, multiply, divide, whatever two variables.

// how to know if an ArrayObject has more elements than other one
var a = new ArrayObject(1,2,3),
b = new ArrayObject(4);
alert(a > b); // false

Above example calls in an implicit way the valueOf prototype methods.
Since latter one returns the length of the ArrayObject, and since b is an ArrayObject with length of 4, the a variable, with only 3 elements, will fail that kind of check.
Another interesting example that could allow us to write less code is this kind of check to know if an ArrayObject has some element:

var a = new ArrayObject(),
b = new ArrayObject(1,2,3);
if(-a)
alert("a has some element");
if(-b)
alert(b); // 1,2,3

Above example shows how to use in a quick and dirty way the valueOf behaviour with an ArrayObject instance. It is the same of:

if(a.length)
alert("a has some element");
if(b.length)
alert(b); // 1,2,3


The "to" prototype and the public static create


In the old ArrayObject version, I used a to prototype to convert a variable into a different one, using a constructor.
The main purpose of the Stack constructor, is to avoid Array.prototype methods assignment, as should be for every other native constructor to avoid problems between libraries.
In this version, the to prototype is only for ArrayObject:

var a = new ArrayObject(4,5,6),
b = [1,2,3].concat(a.to(Array));

In this way we could convert an ArrayObject in every other Array like compatible instance, such Array, or Stack itself.

To invert the conversion, we could use the factory pattern via create.

var a = [1,2,3],
b = ArrayObject.create(a).reverse();
alert(b instanceof ArrayObject); // true


I am working to fix last little problems with my code, but I think both Stack and ArrayObject could be used witout problems, and starting right now ;)

Tuesday, May 20, 2008

Habemus Array ... unlocked length in IE8, subclassed Array for every browser

History


I do not know how many time, during these years, JavaScript Ninjas tried to subclass the native Array to create libraries over its powerful methods without losing performances. I have finally discovered the way to remove locked length from Internet Explorer 8, and to solve problems with every other browser.

We tried to inherit Array instead of Object


This is where my last trip started, simply looking at arguments behaviour. It was there, since 2000 when I started to code in JavaScript, and it was so simple that probably few developers thought about them!

var o = {
length:0,
push:Array.prototype.push,
toString:Array.prototype.join
};

o.push(1,2,3);
alert(o); // 1,2,3

arguments, in JavaScript, is an instanceof Object, and not an Array, as is in ActionScript since version 1.0
What we have done all this time, is to use Array.prototype methods injecting a basic object, with a simple length parameter, inside.
If an object with a length value can be used as an Array, why on heart above code should not work?

We all love prototypal inheritance, we all want an instanceof Array


If you try to inherit directly an array as prototype, Internet Explorer will fix every instance length property, destroying possibility to use simple for loop over generated values.

function MyArray(){};
MyArray.prototype = [];

var a = new MyArray;
a.push(1,2,3);
alert(a.length); // 0 with every Internet Explorer

Problems are much more than a fixed length, as I wrote many months ago when I presented my ArrayObject.
On the other hand, this kind problem has been fixed for Internet Explorer 8, and 7 emulation.
Yes, finally I did it!

/**
* Choose a name for subclassed Array
*/
Stack = (function(){ // (C) Andrea Giammarchi - Mit Style License

/**
* Your personal Array constructor
*/
function Stack(length){
if(arguments.length === 1 && typeof length === "number")
this.length = -1 < length && length === length << 1 >> 1 ? length : this.push(length);
else if(arguments.length)
this.push.apply(this, arguments);
};

// Solution 1:
// Declaration of generic function
// with an array as prototype
function Array(){};
Array.prototype = [];

// Solution 2:
// use the prototype chain to inherit
// Array constructor and its native prototype
Stack.prototype = new Array;

// Solution 3:
// overwrite inherited length with zero value
Stack.prototype.length = 0;

// Solution 4:
// redeclare toString method in this way
// to let JScript core feel better
Stack.prototype.toString = function(){
return this.slice(0).toString();
};

/**
* Return and assign subclassed Array
*/
Stack.prototype.constructor = Stack;
return Stack;

})();

Above code is the basis to create an alternative Array constructor that will be able to work as expected with every browser plus IE8, without length problems.
If you try to remove a single comma from some Solution, it will never work.
If you directly assign an array to the prototype, length will be fixed.
If you remove toString prototype, FireFox and others will not work as expected.

The definitive workaround for every browser


Since first part of this post could be used in every browser, starting from IE 5.5, these old browser can simply use a constructor with a prototype full of native methods, but without instanceof Array behavior.
At the same time, every other cool browser (Safari, Firefox, Opera) could use above code to have the same behavior of IE8.

This is the full cross browser Stack constructor

While this is an improvement over basic JS 1.5 Array, to have JS 1.7 methods too, natives with updated browsers, emulated in a fast standard way with every other.
Stack Extended JS 1.7 Subclassed Array

The last problem to solve, the concat method


concat, is as simple as truly bastard prototype!
There is no way to use native concat method, even with prototypal chain inherited native Array instances.
This is why I have normalized that method, in a Stack self compatible way.
On the other hand, you cannot send a Stack instance as concat parameter, but you can always use native slice method, fast as native one is.

Best performances ever


Yes, using native, incore, prototypes, makes your code execution faster.
This compatibility + benchmark page, can tell you more about this Stack implementation than me, specially with IE8, Safari, and Opera, where performances are neary the same of a generic Array.

FireFox is probably the one that has more problems to manage native code with dynamic constructors, but hey, I am talking about Firefox beta 3, while probably RC1 or nex release will be fast as Safari, or Opera, are.

What to do with Stack?


Libraries, libraries, and libraries, finally with core performaces, the possibility to truly extend the Array, removing every fake iframe, popup, whathever you have used during these days.

Have fun with Stack, and see you soon for some other cool example with them :geek: