Archive for the ‘JavaScript’ Category

Novocode Application Framework 0.4 released

Thursday, May 8th, 2008

I’d like to announce the release of Novocode Application Framework 0.4.

NAF provides a layer of MVC-based GUI components on top of SWT and JFace. A GUI is specified as a tree of NAF components which can then be instantiated as SWT controls. More than just a one to one wrapper of SWT component properties, NAF includes resource management (e.g. shared images and fonts), simplified configuration (e.g. CSS-like size units for layout managers) and model binding. Component trees can be described in a simple XML notation or in JavaScript with an extended JSON format. Applications can also be written entirely in JavaScript. The resource management framework can be used to instantiate and  configure your own classes with a few simple annotations, and it is easily extended for other description or scripting languages.

It’s been a while since the last release which is in part due to design problems with the previous versions, which took me quite some time to resolve. The project still doesn’t have a catchier name :-) but it is now a lot easier to write custom components and the resource management framework can be extended for formats other than XML. The major new feature from an application programmer’s point of view is the JavaScript support.

NAF is licensed under EPL 1.0 and can be downloaded from http://novocode.com/naf/.

Super Constructor Calls in JavaScript

Friday, August 17th, 2007

I have previously shown a simple system for creating “classes” in JavaScript with Java-like inheritance. One limitation of this system is that calling a superclass constructor requires you to repeat the name of the superclass at the calling site:

extcls(Point, function Rect(x, y, w, h)
{
  Point.call(this, x, y);
  this.w = w;
  this.h = h;
})

This is both ugly and unnecessarily limiting. Furthermore, there is no guarantee that the superclass constructor is actually called. In Java, the compiler automatically inserts a super() call at the beginning of a constructor if there is no explicit call to a superclass constructor. This behavior cannot be easily duplicated in JavaScript but it should at least be possible to force an explicit superclass constructor call and throw an exception if such a call does not happen.

We cannot quite use Java’s syntax, either, because firstly, the super keyword is reserved in JavaScript and secondly, we need to invoke the super call through the this object, but we can get close by calling it this.superc (with the “c” standing for “constructor”). Here’s the Rect constructor using the new syntax:

extcls(Point, function Rect(x, y, w, h)
{
  this.superc(x, y);
  this.w = w;
  this.h = h;
})

Where and how can this superc function be defined? The previous example with a base class and one subclass makes it look deceptively simple. Let’s add another class to the hierarchy:

extcls(Rect, function ColoredRect(x, y, w, h, color)
{
  this.superc(x, y, w, h);
  this.color = color;
})

When you create in instance of ColoredRect, the this.superc() call in ColoredRect has to call Rect() but the this.superc() call in Rect has to call Point(), and it’s the same this object they’re calling it on! The only way to achieve this is by reassigning superc to the correct function before each constructor is called.

Fortunately, this is possible because superc is always called from the pseudo-constructors that are passed to extcls and these pseudo-constructors are always called from real constructors which are created on the fly by extcls. We can simply assign the correct superc function in the generated constructors before invoking the pseudo-constructors. And we can make sure that superc has been called by having it set a local flag and checking that flag when the pseudo-constructor returns. Here’s the updated extcls function with the new features:

function extcls(parent, init)
{
  var cons = function cons()
  {
    var called;
    this.superc = function()
    { 
      parent.apply(this, arguments);
      called = true;
    };
    if(arguments.length == 1 && arguments[0] === cons) return;
    init.apply(this, arguments);
    if(parent && parent.__init && !called)
      throw new Error("superc() was not called in "+init.name+"()");
  };
  cons.toString = function()
    { return "[Generated constructor for class "+init.name+"]"; };
  cons.__init = init;
  if(parent)
    cons.prototype = parent.__init ?
      new parent(parent) : new parent();
  if(init.name) self[init.name] = cons;
  return cons;
}

Note that the superc() call may be omitted if no parent class has been given (in which case object is used) or if the parent class is a plain JavaScript constructor that was not defined by defcls or extcls.

Class Constructors in JavaScript

Monday, August 6th, 2007

If your previous experience with object-oriented programming has been in “classical” OOP languages like Java or C++, JavaScript’s prototype object system probably seemed strange at first. When I picked up JavaScript, it was one of the key parts for me to learn. I just wanted to see what possibilities it affords you and how a traditional class model with virtual methods, constructors, hidden state and inheritance could be mapped to JavaScript.

It turns out that a single class (if you can call it that in a classless language) is easy enough:

function Point(x, y)
{
  this.x = x;
  this.y = y;
}
 
Point.prototype.toString = function()
{
  return "(" + this.x + "," + this.y + ")";
}
 
var p = new Point(1,2);
console.log(p.toString());

Running this code gives the expected result: p = (1,2).

Now let’s write a class Rect which extends Point and adds two more fields, for the width and the height of the rectangle. The standard approach you’ll find in JavaScript tutorials is to call the Point function to create a prototype for Rect:

1
2
3
4
5
6
7
8
9
10
11
function Rect(x, y, w, h)
{
  Point.call(this, x, y);
  this.w = w;
  this.h = h;
}
 
Rect.prototype = new Point();
 
var r = new Rect(3,4,5,6);
console.log(r.toString());

Since we haven’t provided a toString method for Rect, the call to toString is delegated to Point’s original implementation, so the result is (3,4).

Line 8 highlights the problem with this strategy: You have to call the superclass constructor to create the prototype! In many cases this is not an issue. In fact, in the Rect example above, the constructor will simply assign the value undefined to the fields x and y of the Rect prototype, but if you want to be able to treat the superclass as a black box, you need a way of subclassing it without calling its constructor on a dummy prototype object.

Unfortunately, you must call the constructor to create the prototype, but you can move the initialization code to a different function instead. The actual constructor can then be created automatically by this helper function:

function extcls(parent, init)
{
  var cons = function cons()
  {
    if(arguments.length == 1 && arguments[0] === cons)
      return;
    init.apply(this, arguments);
  };
  cons.toString = function()
  {
    return "[Generated constructor for class "+init.name+"]";
  };
  cons.__init = init;
  if(parent)
    cons.prototype = parent.__init ?
      new parent(parent) : new parent();
  if(init.name) self[init.name] = cons;
  return cons;
}
 
function defcls(init)
{
  return extcls(null, init);
}

The Point and Rect classes can now be defined like this using defcls and extcls:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
defcls(function Point(x, y)
{
  this.x = x;
  this.y = y;
})
 
Point.prototype.toString = function()
{
  return "(" + this.x + "," + this.y + ")";
}
 
extcls(Point, function Rect(x, y, w, h)
{
  Point.call(this, x, y);
  this.w = w;
  this.h = h;
})

Another problem remains with this code. On line 18, the Rect constructor has to call its super constructor Point() explicitly by name, and the syntax is similar when you override a method and want to call a method of the superclass. What’s missing here is Java’s super keyword. But I’ll leave that for another post.


Close
E-mail It