Kicking the tires on SproutCore, not keen on the object literals

2008-06-19 04:33:00

Started kicking the tires this evening on SproutCore, Apple's "Cocoa-inspired" JavaScript framework for buildling Web applications.

It looks pretty solid so far, although not nearly as far along as some of the older frameworks like Dojo, YUI, or even JQuery. The docs look pretty good, and rather than trying to take a server-language-agnostic approach, it integrates tightly with Ruby, which is personally appealing for me -- I like Ruby a lot, and my job at Seesmic has me doing a lot of server-side stuff in Ruby.

The Hello World tutorial is nicely done -- it does a good job of demonstrating how easily you can get a dynamic Web UI using some Ruby helpers in Erubis rhtml templates.

SproutCore works hard to provide some MVC-sanity for your Ajaxy Web app project, so files are organized logically into separate directories. Your JavaScript controller logic is kept in .js files in a controllers directory.

The only thing I've found remotely disagreeable so far with SproutCore is that, like the other Ruby-friendly library, Prototype, the syntax leans heavily toward JavaScript object literals for pseudo-class definitions.

You create your controller by passing an object containing the properties and methods desired to SC.Object.create, like so:

HelloWorld.appController = SC.Object.create(
/** @scope HelloWorld.appController */ {
  greeting: "Hello World!",
  toggleGreeting: function() {
    var currentGreeting = this.get('greeting');
    var newGreeting = (currentGreeting === 'Hello World!') ?
      'I am on SproutCore!' : 'Hello World!';
    this.set('greeting', newGreeting);

I'm not keen on this syntax for creating objects for a couple of reasons.

One is the small-but-irritating trailing-comma problem with object literals. Some browsers, like Firefox, don't really mind them. Internet Explorer's JScript parser chokes on them like a fraternity pledge on his eighth shot of tequila.

When I lived in Japan, there was this local pub with a door that was ridiculously short -- the top of it hit me right around chest-level (I'm not a tall man), and you had to remember when entering and exiting to bend down to get through the door. I bumped my head on that thing time after time (as did all the locals -- it wasn't just a gaijin thing), cursing every time because I knew to duck my head.

The trailing-comma-separator problem in JavaScript is the same kind of problem as that goofy door -- you keep banging your head on it, even though you should know to be careful with it. Avoiding those object literals for something as ubiquitous as declaring your pseudo-classes makes it a lot less likely you'll be smacking your head on it over and over.

The other big downside of the object-literal syntax for pseudo-classes is that you don't get any local scoping, so you're reduced to using the underscore-propery-name convention to fake private variables. They're still public members, but you just pretend they're private. It's not unworkable, but it's much nicer to have access to actual private variables in your code.

There are a couple of alternatives to the object literal. You can use function objects in a couple of ways:

var foo;
// 1. Object literal
foo = {}; 
// 2. Execute a function that returns an object
foo = function () { return {}; }();
// 3. Use the 'new' keyword, return an obj by default
foo = new function () {};

All of those will return an object. Number two gives you private variables, but the final object you pass back still has to use the annoying object-literal syntax. Not much of a win.

Number three gives you private variables, and lets you use the normal idiomatic "this" syntax you're used to from writing plain old OO JavaScript.

Let's see how SproutCore's Hello World tutorial might turn out using the inline constructor function syntax from number three:

HelloWorld.appController = SC.Object.create(
/** @scope HelloWorld.appController */ new function () {
  var _strings = { 
    HELLO: "Hello World!",
    SPROUT: "I am on SproutCore!"
  this.greeting = _strings.HELLO; 
  this.toggleGreeting = function () {
    var currentGreeting = this.get('greeting');
    var newGreeting = (currentGreeting === _strings.HELLO) ?
      _strings.SPROUT : _strings.HELLO;
    this.set('greeting', newGreeting);

Notice I added a private variable, _strings, to the controller pseudo-class. (I name private vars with a leading underscore to make it clear in my code that it's not a plain local variable -- but it's a real private variable.)

This also looks a lot better to me -- it's a wee bit more verbose with the repeated "this," but it looks to me more like the plain idiomatic JavaScript I'm used to, and there's no worry about smacking your head on that trailing-comma-separator problem.

SproutCore looks pretty reasonable so far. I hope to post more as I get more familiar with it.


Charles Jolley (2008-06-21)


Nice to see your feedback on the SC model. I hear what you are saying about setting things up in the init methods, but the problem is that there is a significant performance penalty there; especially if you are creating objects in a tight loop.

The object literal syntax creates one object that is used over and over. It keeps the work done for each instance creation to a minimum. That is why SC uses that model.

That said, if you prefer the other way, just FYI, you can implement an init() method on your object and setup a lot of things that way also. Just be sure you call the “super” init function using our magic string arguments.callee.base.apply(this, arguments); i.e.:

MyClass = SC.Object.extend({ });

init: function() {
  arguments.callee.base.apply(this, arguments) ; // calls super.init
  // do your setup here...

mde (2008-06-23)


Excellent, thanks for this. I was looking for the way to do this in a more idiomatic SproutCore way.

I can see where performance issue could be a problem. However, I guess thinking about it, inner scope for private variables is most useful at the level of code modules—not something you’d generally be creating in a loop. The utility is less for data objects that you’d have lots of copies of. (That still leave the syntax issue, but that is a matter of taste, more than anything else.)

I’ll dig into the SproutCore object-extension/creation code, and play around with ‘init.’ Thanks again. :)



This is the blog for Matthew Eernisse. I currently work at Yammer as a developer, working mostly with JavaScript. All opinions expressed here are my own, not my employer's.


Previous posts

All previous posts ยป

This blog is a GeddyJS application.