Wednesday, April 15, 2009

Conference Tour: JSConf, Next, SWDC

Making final arrangements for my (first) "conference tour" this summer:

I'll be at JSConf at 24th and 25th of April in Washington, DC, probably speaking about Joose on Track B.

Next up is my employer's own Next Conference here in Hamburg. I'm still actively working on the presentation. The topic will be "Building Postmodern Web Applications". I'll look into the building blocks of the post Web 2.0 era web applications and I'll be talking about applying techniques from 90s era desktop apps to the kind of web apps we'll be building. My general example will be the bespin browser-based source code editor which is my current favorite open-source project.

Last but not least, I'll be at the Swedish Web Developer Conference in Stockholm, once again talking about Joose and maybe some other stuff. Here is the summary of my talk:

Joose - JavaScript 2 Enterprise Edition
Come see how we turn JavaScript from a beautiful expressive light weight programming language into a slow, committee driven, 500 pound beast. Oops.^M
Joose is a self-hosting meta object system for JavaScript with support for classes, inheritance, mixins, traits, method modifiers and more that aims to make object-oriented programming with JavaScript expressive, declarative and very productive. The talk will introduce the core features of Joose, show how the object system can help you WriteBetterCode (TM) and walk though examples and the code that drives them.

Tuesday, April 14, 2009

The Joose Mutability branch

Nickolay has been hard at work pushing new features into Joose and refactoring the core to make it more accessible and extendible. Here is a feature of his work taken from the mailing list (be aware that this is core stuff. None of it should shine through to user level, although there are some nice new things comming out of it):

The sources are now divided into 3 "meta-levels".

Level 1 - Joose.Proto

This level uses the same inheritance principle, as ExtJS framework. Later I found out, that its
called "Crockford object model" (http://javascript.crockford.com/prototypal.html)
As an addition to this model, it possible to use this.SUPER() calls

Class definition at this level looks like:
TestClass = new Joose.Proto.Class('TestClass', {
isa : SuperClass,

attr1 : initValue1,
attr2 : initValue2,

method1 : function () { ... },
method2 : function () { ... }
}).c;
By default every class inherit from Joose.Proto.Object, which contains 'initialize', 'toString', 'SUPER', etc

At this level, attributes and methods are installed directly in class prototype, thus no Roles exists.

Level 2 - Joose.Managed

This level implements a set of classes, which represents "managed" properties.

Class definition at this level looks almost like Joose class:
TestClass = new Joose.Managed.Class('TestClass', {
isa : SuperClass,
does : [ Role ],

have : {
attr1 : initValue1,
attr2 : initValue2,
},

methods : {
method1 : function () { ... },
method2 : function () { ... }
},

after : {
method1 : function () { ... }
}
}).c;
At this level, attributes and methods are represented with instances of special classes. Also appears method modifiers.
Methods are installed not directly but with wrappers, which allow to use the same method in different classes - and implement Roles.

Also - there is no complex attributes on this level.

Level 3 - Joose.MetaClass, MetaRole

This level allows to use complex attributes and class definition looks like normal Joose class:
Class('TestClass', {
isa : SuperClass,
does : [ Role ]
...
});

Mutability

Any class or role, can be extended with following construction:
TestClass.meta.extend({
doesnt : [ Role ],
does : [ Role1],

havenot : [ attr1 ],

...
})
Attributes, methods, roles - can be removed or added. The change will reflect in whole inheritance hierarchy (for classes) or through all composition relations (for roles)

Inheritance

Mutability implied a switch toward single inheritance scheme. I think Roles fully compensate this.

Its safe to inherit from lower "meta-level" - calls to SUPER are transparent.
Inheritance is now cheap operation (due to "crockford model")

Roles


Roles are implemented on Traits spec (http://www.iam.unibe.ch/%7Escg/Archive/Papers/Scha03aTraits.pdf)
They support aliasing and excluding:
    Class('Creature', {
does : [{
role : Walk,
alias : {
stop : 'stopWalk'
},
exclude : [ 'stop' ]
}, {
role : Eat,
alias : {
stop : 'stopEat'
},
exclude : [ 'stop' ]
}]
});
Conflicting properties are marked with conflict markers.

Roles can be applied also to instances (with some limitations)


Class methods

Instead of classical class methods, built-in singletons (symbiont class) are implemented. They are defined via builder 'my' and can contain any usual class builders:
Class('TestClass', {
isa : SuperClass,
does : [ Role ]
...,


my : {
have : { attr1 : initValue1, attr2 : initValue2 },
methods : { method1 : function () { ... } },
does : [ Role ]
...
}
});
they can be accessed as:

if (TestClass.my.attr1 == 'foo') TestClass.my.method1();


Startup time

As inheritance operation is now cheap, startup time for now mostly depends from how many additional roles are applied to metaclasses.

Without additional attributes roles and "depended" roles its the same as for 2.0.
With all those features though, its about twice longer (all measurements were done in FF on Ubuntu)

This can be improved if roles will be applied grouped (not in sequential order), or if the roles will be included to the sources of appropriate classes from start.

SUPER calls (and serialization possibilty)

From start, SUPER calls on "managed" level were implemented with attached properties to wrappers.
Though this reflects on performance (each call to SUPER used up to 2 calls to arguments.callee.caller), so I switched them to use closures, like in current version. So now the SUPER calls are at the same performance, but seriazliation is not possible.

Though, this can be configurable, and if such performance hit is acceptable, serialization can be done (with some additional code)

Btw - about installing JS modules. Yes, Ingy already uses the approach when the JS modules are published on CPAN. Their's sources in his approach lies near the corresponding *.pm files.

And if we'll change the "target installation" directory to something different from standard perl library, we'll get a nice, separate JavaScript lilbrary. Thats the goal, I hope he'll do it.

Otherwise, I'm going to tweak the Module::Build::JSAN for this, it looks not complex.

Wednesday, April 1, 2009

A structured outline view for bespin

After some major parse tree wrestling I finished an experimental structured outline view for JavaScript files in bespin. It's primary feature is that it can be modified at runtime to adapt to your favorite dialect of JavaScript.


While most programming languages have fix constructs like class, namespace or even event declarations, with JavaScript you have to build all these things from simple building blocks. On the other hand, real-world JS code usually follows quite strict rules to build these things. E.g. bespin itself uses dojo to declare "classes" (or constructors, whatever you want to call them) like this:
dojo.declare("bespin.parser.CodeInfo", null, {})
and this pattern to subscribe to and publish events:
bespin.subscribe("parser:error", function(error) {
bespin.publish("message", {
msg: 'Syntax error: ' + error.message + ' on line ' + error.row,
tag: 'autohide'
})
})
With my personal favorite object framework Joose you will find code like this:
Module("Bank", function (m) {
Class("Account", {})
})
While a programmer, who knows nothing about JavaScript will easily recognize the meaning of these statements, JavaScript has to actually execute them to derive the meaning.

My new outline generator works around this problem by being configurable through a kind of DSL which tells the parser more about the specific dialect of JavaScript that you are speaking. Here is the code to tell the parser about the specific pattern that bespin uses to publish and subscribe to events:

bespinEventPublish: {
declaration: "bespin.publish",
description: "Publish"
},
bespinEventSubscription: {
declaration: "bespin.subscribe",
description: "Subscribe to"
}

How it works:
At the heart of the outline generator is a visitor function that gets invoked for every node. It receives a stack of nodes that are lexically before and above it. It also receives a stack of indexes that tell us where a node lies within the child nodes of its parents. This allows finding predessors and successors of nodes above us. Long story short: Once we find a string like "subscribe", we can check our lexical predecessors for "bespin" and assume the next string node is the name of the event. Voila.

Other improvements:
I added an emulation for importScripts for Safari 4 workers that allows loading external source code from the worker. While this is specced, it is missing from Safari. Because Safari workers are also missing XMLHttpRequest I simply abuse the hosting page to do the requests and post the source back to the worker.
This allows removing the narcissus library from the worker bootstrap script and might soon enable us to remove packaging narcissus with bespin altogether.

And an improvement for people using my worker facade: You can now use console.log to write to the console from inside the worker.