Monday, September 8, 2014

Smalltalk Classes in Javascript

In a recent interview in People of ACM Donald Knuth says, "the most common fault in computer classes is to emphasize the rules of specific programming languages, instead of to emphasize the algorithms that are being expressed in those languages. It's bad to dwell on form over substance".

However, while the algorithms and data structures are essential, programming languages do matter!


In another post, I'll discuss the Sapir–Whorf hypothesis as applied to programming languages, but here let me just assert that Object-Oriented languages are widely seen as the best approach for building Graphical User Interfaces.  Javascript is an OO language, but being a prototype-based language (in the style of Self) it does not have the familiar concept of classes, which is a key part of most other OO languages including the original Simula67 and Smalltalk and their more currently popular offspring Java, C#, Ruby, Objective-C, and C++.


Since web programming is primarily GUI programming and the DOM is already object oriented - including subclasses - it is natural to look for a good OO language to use. Of the OO languages, Smalltalk is arguably the simplest and cleanest available, but it is not natively supported in web browsers.  Fortunately, Javascript/ECMAScript is possibly the most widely deployed language of the last 40 years that nobody wants to write in, witnessed by the number of projects to compile other languages to Javascript so we have some options.


Amber is a fabulous Smalltalk environment for the browser (or server, via node.js) including an IDE, compiler, and support environment.  We used it to create a significant environment called Kit which I'll describe in a later post.


The Amber IDE generates Javascript every time you save a Smalltalk method or create a class. When deploying your project you can use just the Javascript and omit the IDE and the Smalltalk source. Unfortunately because Amber implements exact  Smalltalk semantics, the Javascript it produces is pretty unreadable, partly because it passes contexts explicitly.

I was interested to see if I could produce a class system that was more idiomatic Javascript and might have better performance, but still get the Smalltalk semantics correct.

One of the things that Smalltalkers miss the most when forced to work in another language - besides the much simpler syntax and rich class structure - is that in Smalltalk everything is an object, even numbers and classes. This means that objects (including numbers and classes) can inherit from superclasses and be extended with new methods.

There are other libraries for classes in Javascript but none that I've been able to find correctly and fully implement Smalltalk object and class method semantics. One particular challenge is making references to super work properly.

In this post I'll explain a bit about "classes" in Javascript, then in the subsequent posts I'll describe the classes I've made, some usage examples, performance comparisons, and some of the subtleties of implementing this in Javascript. 

While Javascript doesn't have classes, it does have inheritance. Each object in Javascript has a __proto__ field which points to an object where attributes (including functional values) are searched for if they are not found in the object itself (recursively, so if not found there, it looks in that object's __proto__ field, and so on).  Javascript doesn't have classes per se, but it does have the idea of constructors.  A constructor is a function with a prototype field. As an example, consider Foo. When the code new Foo is executed, a new object is created, with its __proto__ field referring to the same object as the prototype field of the Foo function:


      > function Foo(){}
undefined
> Foo.prototype.bar='xxx'
"xxx"
> Foo.prototype.constructor
function Foo(){}
> f=new Foo
Foo {bar: "xxx"}
> f.__proto__===Foo.prototype
true
> Foo.prototype.fu='yyy'
"yyy"
> f
Foo {bar: "xxx", fu: "yyy"}
> f instanceof Foo
true


Note that in Smalltalk new and isKindOf: are simply functions/methods, whereas in Javascript new and instanceof are syntax (new works with any function and instanceof checks if one of its left argument's __proto__ fields (recursively) is equal to the prototype field of the right argument (which must be a function)).  Note that the Javascript operations require the constructor to be a function, but if we implement them, like Smalltalk does, as methods, there need be no such restriction.

In the next post we'll look at the classes I've implemented.