Class Declaration in qooxdoo
This article is a compact overview of object-oriented programming as supported by qooxdoo 0.6.x. It focuses on class declaration, and reveals some of the shortcomings that are being addressed by the proposed new class system for qooxdoo 0.7.
Class Declaration in qooxdoo
A typical class declaration looks like the following:
qx.OO.defineClass("Cat", Feline, function(name) { Feline.call(this, name); }); qx.OO.addProperty({name: "foo", /* ... */}); qx.Class.LATIN_NAME = "Felis silvestris catus"; qx.Proto.favoritePillowType = "soft"; qx.Proto.useLitterBox = function() { // not allowed to use qx.Class here // ... };
Shortcomings in qooxdoo 0.6.x
Not in Closed Form
Class definition is not in a single, “closed” form. For “regular” classes it only combines the definitions of the class name, its super class and its constructor. Unfortunately, all other definitions like instance members, class members, properties, etc. are done somewhere after the initial class definition.
Multiple Signatures
The typical signature of qx.OO.defineClass() has three arguments: class name, super class, contructor. Unfortunately, those are not given as named parameters, but are determined by the corresponding index in the argument list. There is another signature for static classes, that involves only two arguments: class name and a map of static members. While not uncommon in many languages, such multiple function signatures make it hard to easily determine the particular use of the function.
Instance and Class Members
What does the expression qx.Proto mean? Well, its name suggests some relation to the JavaScript prototype property. But since we want to define instance members, something like qx.Instance might - at least - have been more intuitive.
Both qx.Proto and qx.Class are only available on left-hand side of statements. They can not be used inside methods (on the right-hand side). During a call of a method at runtime, these variables do no longer point to the same targets as they did at load time right when the class was defined.
Dynamic Properties
The definition of dynamic properties is awkward as well. The qx.OO.addProperty({name: “foo”,...}) in the example above defines a property foo and automatically generates an accessor method getFoo() and a mutator method setFoo() for each instance of the class. Surprisingly, in qx.OO.addProperty({name: “foo”,...}) there is nothing given that denotes the actual class for which the dynamic property is defined. It is implicitely for the class previously defined in an qx.OO.defineClass() statement. So it behaves like the qx.Proto, but uses the qx.OO namespace.
Superclass Call
Calling the constructor of the superclass from the constructor of the derived class is clumsy and error-prone, while for example in Java it is just a simple super(). The superclass needs to be referenced explicitely by its fully-qualified name like Animal.call(this, name) in the example. If the superclass changes later, all those explicit calls need to be modified...
Many often-encountered generic “solutions” that do not involve the explicit name of the superclass, but instead only use “this” keyword naively, cannot work in principle: they break down for longer inheritance hierarchies, since the context of each calling class in the hierarchy gets lost (see e.g. Danny Goodmann's blog entry).
The only generic solution (to our knowledge) is to additionally use arguments.callee, which always points to the actual function. this on the other hand just holds the current context, which can be transparently manipulated by calling the function from the outside via call() or apply() with a foreign context.
Calling the overridden method of the superclass is equally clumsy and error-prone, as it also involves the explicit superclass name:
qx.Proto.bar = function(arg) { Animal.prototype.bar.call(this, arg); ... }
Again, in Java that would simply read super.bar(arg). Sigh.
Missing Advanced OO Features
A complex software project like the qooxdoo framework with about 300 classes could profit from advanced OO features that allow for a more concise design. Some advanced concepts enable languages that only allow for single-inheritance to tackle problems that would otherwise be solved by multiple-inheritance: interfaces and/or mixins. qooxdoo 0.6 lacks such features, it has
- No support for Interfaces (Java-like)
- No support for Mixins (Ruby-esque)
Outlook
The shortcomings mentioned above are being addressed by the proposed new class system for qooxdoo 0.7.
