ContextJS - Manual
ContextJS is a context-oriented language extension to JavaScript. It allows for defining context-specific behavior variations in modular way. Behavioral variations are expressed as layers which can refine object and class behavior. Layers can be globally activated, dynamically scoped in the control flow of code code blocks and they can be activated depending on objects. For example, in Lively Kernel layers can be scoped in a structural depended way: a layer can be activated for a graphical object and its subobjects.

Introduction

JavaScript is a very simple but powerful language, nearly everything can be change dynamically at runtime. This allows for example to adapt exisiting code for example in libraries at runtime.

a = new Object(); // Properties can be added at runtime a.foo = 'World'; // but adding behavior is no difference... a.bar = function() { return 'Hello ' + this.foo} a.bar() // -> Hello World

This dynamic nature of the language can be used in many ways for adapting existing behavior. One general technique is wrapping existing functionality

a.bar = a.bar.wrap(function(oldFunc) {return oldFunc()+ "!"}) a.bar() // Hello World!

Which is a nice technique for trying out new behavior in a instance-specifically scoped way. But when we continue to develop the new behavior we get into problems....

a.bar = a.bar.wrap(function(oldFunc) { return oldFunc().toUpperCase() + "!" }) a.bar() // HELLO WORLD!!

The new behavior has become the old behavior and if we don't replace we are stuck with it! There is one "!" to much. The problem is that the behavior is now bound the the objects. The solution is to not directly bind the behavior variations to the instance, but to define them in a layer and activate that layer dynamically.

cop.create('ScreamLayer').refineObject(a, { bar: function() { return cop.proceed().toUpperCase() + "!" } }) cop.enableLayer(ScreamLayer) a.bar(); // HELLO WORLD! cop.disableLayer(ScreamLayer) a.bar() // Hello World

Since, now the bevhavior adaption can be scoped, the new and old behavior can coexist in one system, and be active depending on the context. We found this a very valuable feature for developing Lively Kernel from inside a Lively Kernel hosted system. We can safely experiment with core functionality without having to worry to much about shouting ourselfs in the foot. ;-)

Layer Definition

Layers in ContextJS are simple objects. Typically they have a name and are stored in a global variable with the same name, and they inherit from the class "Layer".

cop.create('MyNewLayer')

would be the same as

MyNewLayer = new Layer('MyNewLayer');

The former eliminates the error prone redunant name declaration.

Refine Class

Since, Lively Kernel (the system we developed ContextJS for) is a mostly class based system we have special syntax in ContextJS for layering classes. Classes in JavaScript a only a pattern of using the prototypical inheritance and are no language feature.

In Lively Kernel a simple class definition looks the following:

Object.subclass("Person", { initialize: function(name) { this.name = name }, say: function(something) { alert(this.name + " says: " + something) }, toString: function() { return "Person(" + this.name + ")" } }); joe = new Person("Joe") joe.say("Hello")

Now we can refine the behavor of the function "say" in ScreemLayer.

cop.create('ScreamLayer').refineClass(Person, { say: function(something) { cop.proceed(something.toUpperCase() + "!") } }) enableLayer(ScreamLayer) joe.say("Hello") disableLayer(ScreamLayer) joe.say("Hello")

Layer Activation

Implementation

Examples

Conclusion