Monday, September 29, 2008

Javascript Multiple Inheritance




Since this in the body of a function is the reference to the object used to call the function e.g.



obj.setProp = function(p) { this.prop = p }
obj.setProp(5)
obj.prop
=> 5

and since Javascript constructor function is the same as any other javascript function and the only difference happens through the use of the new operator. We can use this (double meaning) to inject functionality provided by multiple constructor functions (sort of multiple inheritance) into our own objects as long as the these constructor functions are not only natively implemented (e.g. Array, String, Function, .... etc) and that the injected functionalites are not dependent on their prototypes.



function Cat() { this.scratch = function () {alert("scratch!!")} }
function Dog() { this.bite = function () {alert("bite!!")} }
var catyDog = {}
catyDog.catify = Cat
catyDog.catify()
catyDog.dogify = Dog
catyDog.dogify()

Now the catyDog object can both scratch and bite, so you better be careful.



catyDog.scratch()
// alerts "scratch!!"

catyDog.bite()
// alerts "bite!!"

Another way of doing the same thing but keeping the injecting functions kind of private:



function CatyDog()
{
var me = this
this.myownProp = 'special prop'

var init = function() {
me.catify = Cat
me.dogify = Dog
me.catify()
me.dogify()
me.catify = undefined
me.dogigy = undefined
}
init()
}

Using such technique makes it our own responsibility to select which prototype of the constructors to choose for our own constructor and also to choose non-conflicting functionality which is always the case when using multiple inheritance.


In the previous example script if either Cat or Dog constructors had a prototype set, neither catify nor dogify will set the prototype for our object. Only the new operator would do such magic. So we will have to set the prototype of our choice ourselves using __proto__ property or we can set the prototype for our constructor function and rely on the new operator magic.


Now suppose that you need CatyDog to completely inherit Dog (including its prototype) while having Cat functionality.




function CatyDog()
{
var me = this
this.myownProp = 'special prop'

var init = function() {
me.catify = Cat
me.catify()
me.catify = undefined
}
init()
}
CatyDog.prototype = new Dog

var catyDog = new CatyDog

catyDog.scratch()
catyDog.bite()

The difference here is that any inherited Dog property including bite function will be fetched in the prototype each time it is used.

Also here all CatyDog objects will have one single prototype Dog object.
So if you need every object to have its own prototype object can do it this way



function CatyDog()
{
var me = this
this.myownProp = 'special prop'

var init = function() {
me.catify = Cat
me.catify()
me.catify = undefined
me.__proto__ = new Dog
}
init()
}

var catyDog = new CatyDog

catyDog.scratch()
catyDog.bite()

Easy Application Development for the iphone




Most Developers who are new to the stormy currents of iphone development in Objective-C would stay at the shores for quite some time before they get their boats wet and start sailing.
But with Jiggy at hand, development for the iphone would be a walk in the park for most developers who are familiar with Javascript. It's really nice to use such a flexible and powerful language to script your applications.
Since Jiggy runtime wraps native Objective-C API for you. You won't even need a compiler or the tool chain to start developing. All you'll need is a browser on your machine and a jailbroken iphone with jiggy runtime and jiggy (ide) installed and you can start writing your native applications in javascript. (You can get Jiggy from here)

What you have to do


Run jiggy on your iphone, that would start its own web server that you can log on to from your browser by going to the url shown on jiggy screen and typing the user name and password (both are "jiggy" initially)
Now you can write, save and run your application form your browser ide.


What actually happens


Running the application actually runs a 17K bootstrap executable called jiggy (of course) which is included with every Jiggy application you write. this executable loads the Jiggy runtime and evalutes and executes your javascript code which should be in main.js file.
Jiggy Runtime is a collection of Jigglins ( Objective-C dynamic libraries that expose part of the Objective-C API to Javascript)
Jiggy Runtime can be extended by building new Jigglins that expose more of the native API.


An example


A Hello world marquee application.



// main.js
Plugins.load( "UIKit" );
include( "marquee.js" )
var window = new UIWindow( UIHardware.fullScreenApplicationContentRect );
window.setHidden( false );
window.orderFront();
window.makeKey();
window.backgroundColor = [ 1 , 1 , 1 , 1 ];
var mainView = new UIView();
window.setContentView( mainView );
var bounds = [0,0,window.bounds[2],20]
var delay = 4
var marquee = new Marquee( "Hello World", mainView, bounds, delay )
marquee.onStop = function() { marquee.start() }
marquee.start()

Well since the UIKit plugin does not provide Marquee constructor I had to write one myself and include it before using it in main.js.
But the good news is I wrote it in Javascript.

I made use of components already provided by the UIKit plugin namely UIScroller, UITextLabel, UIFrameAnimation and Animator.

Here's the trick.

A UITextLabel holds the text and using an animation it crosses the width of it's container view, a UIScroller.

The animation starts with the text label totally hidden beyond the right border of the scroller and stops when it totally disappears beyond the left border.

The delay passed to UIFrameAnimator should be the total time of the animation in seconds.

So that delay for the Marquee, the time taken by text in the marquee to cross the width of the scroller, had to be corrected before passing it to the animation constructor.
If you're interested here's the source.



// marquee.js
function Marquee(text, parent, bounds, delay, onStop) {
var me = this
var scroller = new UIScroller(bounds)
var label = new UITextLabel([bounds[2], 0, bounds[2], bounds[3]])
label.text = text
scroller.addSubview(label)
parent.addSubview(scroller)
var startFrame = label.frame
startFrame[2] = label.textSize[0]
label.frame = startFrame
this.delay = delay ? delay : 10
this.onStop = onStop ? onStop : null
var scroll
var correctDelay = function(delay) {
var w = scroller.bounds[2]
return delay * (label.frame[2] + w) / w
}
this.start = function() {
var endFrame = startFrame
endFrame[0] = -endFrame[2]
scroll = new UIFrameAnimation( label , 3, startFrame , endFrame )
scroll.onStop = this.onStop
Animator.addAnimation(scroll, correctDelay(me.delay), true)
}
}

If you're interested in a more complete Marquee constructor check this one out.