I happened across an interesting little project today. A project to create a Javascript GUI framework by one Greg Houston who, by an amazing coincidence has decided to design it in a way that's similar to my own framework. And by another stunning coincidence he has chosen to name it... Mocha. How peculiar. How peculiar indeed. Is this a case of blatant theft of an idea? I'm flattered if it is, for two reasons: 1) It validates the idea, and 2) It means people know who I am. Shocked, tho I am, I'm also not angry. I'd like to be. It's been my concern that my stupid dilly-dallying on this project would find me outpaced by the less visionary but more diligent and organized and until now I had every reason to believe that that concern was merely my imagination, but it seems I was right, at least to some extent. Well again I'm vindicate in my views, tho this vindication is perhaps less desirable. However, it doesn't matter. The framework I'm (not-so-often-ly) working on was always going to be open source anyway, given the obvious inability to hide JS code from prying eyes. However I'm saddened no one thought to even mention this alternate project to me. Perhaps Greg doesn't even know who I am, and merely came up with this in parallel, but the similarities are too great. Perhaps we share a mutual friend and without realizing was informed of the idea I had and set out on his own to create what he thought was a good idea, not realizing the idea was actually a memory of something. Either way, it is what it is. To that end I feel I might as well open up what little I have so far to the world. I warn you: it's not pretty -- I don't pretend to be a great programmer, or even a good programmer -- it's horrendously slow (I'm working on a new way to implement class-based inheritance in JS so that it runs faster than what I've currently got, which will obviously be rendered pointless in JS2 but such is life, ey?), and it's far from being done, but it is everything I have worked on so far. So here it is, the original Moka, not yet complete but in its current entirety:
I just watched the three most important TED2007 talks. They all talk about related (albeit abstractly so) concepts that all tie in to what I think will be a very important technological achievement in the coming decades: the development of an abstract theory of self-organization.
Neil Gershenfeld: The beckoning promise of personal fabrication — Fabricators and the ability to "print" whole objects. (Once we have this technology, the entire social, economic, and political landscape will change. Watch out!)Saul Griffith: Hardware solutions to everyday problems — Self organizing structures and their application to current problems.Paul Rothemund: Casting spells with DNA — An exploration of the way in which chains of amino acids and other molecules can be coerced into specific shapes simply by programming them.Hod Lipson: Robots that are "self-aware" — Designing robots that can determine their own body configuration and learn how to achieve tasks, without any outside guidance.Vilayanur Ramachandran: A journey to the center of your mind — How brain damage can provide insight into the functioning of the brain.
Also worth listening to:On Intelligence by Jeff Hawkins — Hawkins' magnum opus sketching out a view of the design of cognitive structures.Futures in Biotech 10 — Carla Shatz on self-organizing brain structures.Futures in Biotech 20 — Eric Kandel on the mechanisms of memory and learning.This one's going to be short.
:name"name"function $(name){$nameI recently discovered this thing called Functional Javascript, which contains a number of quite sexy modifications to Javascript's base classes to add extra, more functional things. While I was browsing Oliver Steel's blog, I came across his Javascript memoizer.
foo.bar = function(){ ... }foo.bar = function(){ ... }.memoize();x = function(){ ... }.method();function(){ ... }. method();function(){ ... }(function(){ ... })So after talking with Brian about what we should call the framework, now that it's clear we can't use Jade, we've settled on Moka, as a short form of Mocha. We decided to go with an alternative spelling to avoid potential confusing with MochiKit. We also figure that since the framework is going to have two primary skins, one light and one dark, we can come up with cute little coffee-based names for each skin.
Naming Issues
Brian, the guy I'm going to be doing this whole startup thing with, pointed out to me that theres already a framework named Jade, for Java. My instinctual reaction was to discount it. I mean, it's JAVA, c'mon. Evil language. But once reason returned I had to concede that a new name would be needed. This means I'll have to change all the code for my framework, since all Jade classes have "Jade" as a prefix (e.g., "JadePanel"), which is a direct inspiration from the NS prefixing in OpenStep.
Progress and Preparation
Jade (or whatever .. *grumble*) is now really rather close to being ready to go into alpha testing, which Brian points out is going to require a site and all the accoutrements that go along with having a project like this. So far it seems like we'll need at LEAST info about the project, some sort of blog or forum or similar for building a community, documentation for the framework, and of course site design, server space, and a domain name. Oh boy.
Pretend file systems, URLs, and XHR
Obviously if you're gonna have apps, you're going to want to upload and use files so you need some sort of file system. Also, since it's web based, there's going to be significant use of URL manipulation and XMLHttpRequest usage. But these are all kind of the same on the web, aren't they? URL's reference files on a server, XHR allows you to perform HTTP requests for files, and a file system is just a way of handling files. So I've made the decision to collapse functionality into a single URL class that will let you perform URL manipulation and XHR interactions with the server seamlessly.
Ok, so for a while now I've been woefully undereducated on the uses of try...catch. I know, I know, how can I claim to know JavaScript beyond even a basic level without knowing try...catch. Ok fine, sue me, denounce me as a poser, MEA CULPA. :P
Why is this relevant to the title? Well for a while now I've been manually checking argument type like so:
function doSomething( aJadeObject ){
if( aJadeObject == undefined ){ return; }
if( typeof(aJadeObject.isKindOfClass) != "function" ){ return; }
if( !aJadeObject.isKindOfClass(NecessaryClass) ){ return; }
//blah blah blah...
}
The first line verifies that the argument is defined, because if it's not the second line will destroy the script. The second verifies that the object responds to the JadeObject method that's used to test descent from a particular class. The third actually verifies that descent. I did this for obvious type-checking purposes. I don't want to sent JadeArray query messages to a number or to null and kill the program, do it? No. Instead it would be better if bad messages just returned some default or null value or something, so that in such a case, the program would still function but there would just be a minor, localized, and likely unnoticeable, fault, instead of taking the entire thing down.
This whole convoluted system came up in a discussion with the ever patient Emmanuel Zephyr, my Cocoa devver friend person. I asked him his opinion on what sort of values should be returned when the function by default is supposed to return some none-void value. His suggestion was that i shouldn't even bother with all of that but instead should just use try...catch, which would simply try to perform the necessary operations without crashing the script. If the objects in question respond to the necessary messages then the try block will work successfully, which means that as far as the script cares, the arguments were the right type, otherwise it would fail and no bad things would happen.
So instead of all of that junk above, it would reduce to...
function doSomething( aJadeObject ){
try {
//blah blah blah...
} catch(e){
//maybe log the error?
}
}
without any type checking at all, and with a potential area for handling these type errors, possibly with some sort of logging for later debugging. I can't really believe that I allowed such a useful tool as try...catch slip past my dradis, but that's life, ey?
My only concern is this:
var x = 0;
try {
x = 5;
y++; // throws an exception because y is undefined
}
alert(x); // alerts 5, because the x = 5 assignment works, despite the try block containing exception-throwing code.
This is potentially problematic because there might be cases where something is added to an array or whatever on the assumption that it's a certain type of object, and then it gets sent a message that it doesn't know how to respond to because it's not that type of object. So now the try fails but the object is still in the array, which is probably not a good thing. Now, this might not be a huge issue, and any problems that it might cause probably won't be too hard to fix, but it's definitely not perfect. Oh JS2, where art thou?
Quick status update:
Total classes currently in the Jade framework: 83.
Total classes completely finished: 42.
That means that atleast 51% of the framework is completely finished. Not counting the mostly finished and partially finished classes.
This is a wonderful milestone. :)
Ok, so maybe I went a bit overboard with the JavaScript thing before, and then slacked off a whole lot, but I wrote a bunch for you! All.. none of you. But I've returned!
I just want to comment on the development process real quick, and on the importance of understanding the way you're going to implement things before you dive in and implement them.
While I was beginning with the design for Jade in the latter portion of last year, I decided that Views, the things that get displayed on the screen, would have to have a dedicated Div that would hold all it's stuff. I called this the Page Display, because obviously it's the part of the View that gets displayed on the page. Everything would get dumped in that, absolutely everything.
Now, after looking a bit more at the design of NSClipView (for those of you who don't know, Jade is based primarily on OpenStep, hence the NS~ class names), I realized that NSClipView moves its bounds rect to change what part of a NSTableView is shown.
Basically the bounds rect is the rect in the View's own coordinate system that gets drawn to fit within the frame of the view, as it's displayed. For Jade, this doesn't exist; the View's coordinate system is fixed, with (0,0) at the top left corner of the view's page display, and that's just the end of it, so there's no way to move the coordinate system around within the view.
This is relevant for the JadeClipView class because I'm currently clipping simply by moving the content around within the clip view's coordinate system, so that the content's actual position is changed. With NSClipView, on the other hand, the position of the content doesn't change, it's the coordinate system as a whole that moves.
Why is this an issue? Well it means that if you have a TableView (or any other view, really) within a ClipView, the NSTableView would always remain at the same position, and so anything depending on that position can work fine, whereas the JadeTableView will be moving around, and that could cause problems with whatever might depend on those coordinates.
The fix, as far as I can tell, would be to create another Div within the Page Display, perhaps called the Drawing Canvas (not to be confused with the Canvas tag, which might actually be used later in an actual non-html based drawing system), and draw everything into the Drawing Canvas, and move that around to change the bounds rect.
Doing this wouldn't be a huge difficulty, seeing as how it's mainly going to involve replacing all the references to the Page Display when drawing, but thats about 30 or 40 classes at this point. Still, now as major a reworking as the variable privatizing I did last month, which took two or three days of almost non-stop coding and debugging and easily over a thousand manual replacements.
So the moral of the story is that had I planned this out more fully in the beginning, and attempted to keep with fairly strict adherence to OpenStep, I wouldn't have to change 30 draw methods, they would've just been the way I needed to begin with.
No, not the bastard lovechild of Superman and Crystal Method.. Super methods are methods that belong to the class that's being inherited from. It's possible to retail these methods even after they've been re-defined, by providing a nice new method to the Object class prototype.
What we'll do is create a convenience method that will take care of the inheritance for us, and include a little bit of code to make super methods available:
Object.prototype.extend = function( Class ){
Class.apply(this);
var supers = {}; // not "super" because that's a reserved keyword in JS
supers.constructor = this.constructor;
for( var m in prototypical ){
supers[m] = this[m];
}
this.supers = function(){
var dupe = {};
for( var m in supers ){
dupe[m] = supers[m];
}
return dupe; // use private variables and a duplicate to prevent destruction of the original supers object
}
}
With this, we can now extend other classes while retaining the ability to utilize their methods if needed:
function A(){
var foo = "bar";
this.getFoo = function(){ return foo; }
}
function B(){
this.extend(A);
var baz = "bop";
this.getFoo = function(){ return baz; }
}
var b = new B;
alert( b.getFoo() ); // alerts "bop" because we overrode the definition of getFoo
alert( b.supers().getFoo() ); // alerts "bar" because it accesses the supers' method
In this picture, we can see what occurs when we have simply a super object to contain super methods. This would result from the basic extend of Object, in the constructor A. We can see the relationships between the context object, this, which has a super object and some method some method foo, which has access to the context of A, which contains the context object as a variable:
Next we can see the result of an extend of A with a super object to retain the methods for use later:
In this image you can see how we've added the original foo method to the super object, replaced the existing super object with the new one, and also created the new foo method with B.
Incase you're worried that this is smoke and mirrors, and that the super methods simply work on different variables, let's not override anything but instead have a setter method as well:
function C(){
var foo = "bar";
this.getFoo = function(){ return foo; }
this.setFoo = function( newFoo ){ foo = newFoo; }
}
function D(){
this.extend(C);
}
var d = new D;
alert( d.getFoo() ); // alerts "bar", as expected
alert( d.supers().getFoo() ); // alerts "bar" as expected
d.setFoo( "baz" );
alert( d.getFoo() ); // alerts baz, as expected
alert( d.supers().getFoo() ); // alerts baz
So we can see that the supers' methods and the objects methods both have access to the same scope variables, and why shouldn't they? After all, all we did was add a reference to the methods into the supers object. If we don't override the method, then both the object and it's supers object reference the same method, but if we do, we still retain the original method in the supers object.
Also worth noting is that I chose to define the constructor of the supers object as the constructor of the current object. I did this because it's often very convenient to create methods that create new versions of themselves. For instance, if we have a TwoDPoint class that has a method that does something like "new TwoDPoint", and then created a ThreeDPoint class that extends TwoDPoint, the inherited method will still produce a new TwoDPoint, even if it should be creating a new ThreeDPoint. This is avoidable by doing "new this.constructor", which will created a new instance of the same type of object that's executing it, regardless of how deep in an inheritance hierarchy.
Now, if we hadn't set the supers' class, we would have the small problem of not being able to use super methods that have that functionality. Why? Well when you call a super method, the object that's calling it, which also happens to be the context object, is not the object that you're sending the method call to, but rather the supers object. If there are any methods that do "new this.constructor", it will reference the supers object's constructor. If we had not defined it, it would default to Object, and had we defined it as anything other than the current object's constructor, like say Class (which seems reasonable), we wouldn't get a new version of the current object. Both are troublesome! But the fix is elegant and simple.
I hope you learned something from this! Next time I'll be going over class methods and inheritance with them. Have fun, and don't forget to experiment with JavaScript!