Noumena

SScript: enhancing JavaScript’s expressive power

sqlogo2.gifSScript is a JS library that adds methods to common classes (like Number, String, Function, Array, Boolean, etc) in order to make them behave in a pure object oriented manner. Most of the methods (or messages) were inspired by Smalltalk’s Squeak! dialect, and adapted to JavaScript. SScript also enhances JavaScript expressive power by adding “String Blocks”, blocks with arbitrary number of instructions formed by strings of the type ":x :y | ^x > y". SScript adds powerful Smalltalk Collection methods to the Array Class like _collect, _inject_into, _select, _reject, _do, _sort, etc. Finally, SScript also incorporates Boolean and Number instance methods for condition clauses and iteration clauses. For a more detailed description of this library you can read the examples below or go to the API reference page.

String Blocks

Blocks are useful pure object oriented expressions of the form [:x :y | ^x > y]. This expressions are often not evaluated until a unary (or keyword) message is sent to them like [:x :y | ^x > y] value: 4 value: 5.

SScript allows you to create blocks from strings using the method _asBlock. This way, SScript lets you write expressions of the form ':x :y | ^x > y'._asBlock();. The expression can be mapped to the more verbose javascript form function (x, y) { return x > y; } and thus evaluated by applying parameters like ':x :y | ^x > y'._asBlock()(4, 5);.

Array methods

SScript adds methods to the Array class to make it behave like a Smalltalk Collection. By adding methods like _do, _collect, _inject_into, _select, _reject and _sort you can now have a taste of the compact and powerful methods of Smalltalk. Let’s see some examples:

[1, 2, 3]._collect(':x | ^x+1');
-> [2, 3, 4]

[1, 2, 3, 4]._select(':x | ^x > 2');
-> [3, 4]

Some more examples:

[1, 2, 3]._collect(':x | ^x*2');
-> [2, 4, 6]

[1, 2, 3]._reject(':x | ^x > 1');
-> [1]

multiplying the numbers in an Array:
[1, 2, 3, 4]._inject_into(1, ':x :y | ^x*y');
-> 24

adding the numbers in an Array:
[1, 2, 3, 4]._inject_into(0, ':x :y | ^x+y');
-> 10

sorting numbers:
[1, 10, 7, 8]._sort(':x :y | ^x < y');
-> [1, 7, 8, 10]

[1, 2, 3]._sort(':x :y | ^x > y');
-> [3, 2, 1]

sorting objects:

var a= {
x: 1,
y: ‘howdy’
};


var b= {
x: 4,
y: ‘howdy’
};


var c= {
x: 2,
y: ‘howdy’
};

[a, b, c]._sort(':w :z | ^w.x < z.x');

-> [a, c, b]

Iterative Constructions

String blocks inherit all block methods, so iterative constructions like

var counter= 0;
‘^counter < 5′.whileTrue(’counter._print(); counter++;’);

can be created. The above example will show alerts for “0″, “1″, “2″, “3″ and “4″.

The above code would have been written in Smalltalk as:
[^counter < 5] whileTrue: [counter printOn: Transcript. counter:= counter + 1]

This code would have been equivalent to:
while(counter < 5) {
alert(counter);
counter++;
}
in usual JS.

SScript also extends the Number class in order to iterate like this:

(5)._to_do(10, ':counter | counter._print();')

this code is just like Smalltalk’s:

5 to: 10 do: [:counter | counter printOn: Transcript]

the usual JS code for the above example is
for(var counter= 5; counter <= 10; counter++)
alert(counter++);

Math methods are Number messages

The Number class has also been extended with the applicable Math methods.  So if the distance between two objects is calculated in JavaScript as:  

Math.sqrt((anObj1.x - anObj2.x) * (anObj1.x - anObj2.x) + (anObj1.y - anObj2.y) * (anObj1.y - anObj2.y));

It can be transformed into this:

((anObj1.x - anObj2.x)._squared() + (anObj1.y - anObj2.y)._squared())._sqrt();

See the API reference page for more information about the Math methods included.

Boolean messages

The Boolean class has been extended to support conditional expressions of the form:

(0 > 1)._ifTrue(' "howdy partners!"._print(); ');

This would have been written in Smalltalk as:

(0 > 1) ifTrue: ["howdy partners" printOn: Transcript]

The above code in usual JS is

if (0 > 1)
alert(”howdy partners!”);

Fibonacci function:

usual JS:
function fibo(n)
{
if (n < 2) return 1;
return fibo(n-2) + fibo(n-1);
}

SScript:
return (this <= 2)._ifTrue_ifFalse(’^1′, ‘^(’+this+’ -1).fibo(); + (’+this+’ - 2).fibo();’);

Smalltalk:
^self <= 2 ifTrue: [1] ifFalse: [(self - 1) fibo + (self - 2) fibo]

Please, drop by the API reference page to see all non mentioned methods.

Developement

SScript seems to merge pretty well with the common use of JavaScript. Its pure object oriented nature enhances JS with the power and beauty of Smalltalk like languages and simplifies common array manipulations. Number instance's' "math" messages free us from painful constructions  involving the Math class and better adapt to pure OOP. This methods may prove really useful when doing arithmetics, as  in canvas JavaScript programming.

Disadvantages

  1. Even if String Blocks are a more elegant and concise way to create anonymous functions, they lack context. That means that all variables used in string blocks must either be passed as formal parameters (like :x) or global variables.
  2. Due to the restriction above mentioned, iterative pure object oriented constructions (like ifTrue or whileTrue) must be kept simple when using String Blocks.
  3. All this problems can be solved by using anonymous functions (i.e. function () { … }) instead of String Blocks.
  4. Finally, the expressive power of pure object oriented languages lies in block constructions and collection manipulations, which this library is built to provide. All iterative and boolean expressions are maintained for pure OOP consistency.