Jay Phelps

Loves code, hates condiments • CTO at Pivotshare • Costa Mesa, CA

Jul 5, 2013

Now that Ember.js is approaching 1.0 status, I've finally started using Ember for several real-life projects; most of which are rather complex. As they began to grow, I discovered several common imperfections or "gripes" about using Ember.

One of them is the heavy use of this.get('foo') + this.get('bar') all. over. the. place. Apparently, I'm not alone. Most newcomers I've introduced Ember to have similar complaints.

So I set out to mitigate getter-hell by borrowing a concept from many popular programming languages: String interpolation. In this form, instead of interpolating variables from the local scope1, we're interpolating properties from an object. The project is hosted on Github and is called Ember.String.interpolate.

Here's a quick taste:

'Robot status is: $status'.interpolate({ status: 'online' });
// 'Robot status is: online'

First thing I did was create the generic String interpolation code that is library agnostic, befittingly called String.interpolate.js. This buys us the syntax above and can be used with vanilla JavaScript or any library of your choice.

Ember Computed Properties

Now that we've got a library that'll do String interpolation, the next step is fully leveraging Ember to streamline our code.

Here's a pattern seen often in Ember projects:

App.Person = Ember.Object.extend({
    firstName: 'Bilbo',
    lastName: 'Baggins',

    // Bilbo Baggins
    fullName: function () {
        return this.get('firstName') + ' ' + this.get('lastName');
    }.property('firstName', 'lastName').readOnly(),

    // Welcome, BILBO BAGGINS!
    welcomeMessage: function () {
        return 'Welcome, ' + this.get('fullName').toUpperCase() + '!';
    }.property('fullName')
});

It's not that bad…but it's certainly not ideal. We can do better! With Ember.String.interpolate:

App.Person = Ember.Object.extend({
    firstName: 'Bilbo',
    lastName: 'Baggins',

    // Bilbo Baggins
    fullName: '$firstName $lastName'.interpolate().readOnly(),

    // Welcome, BILBO BAGGINS!
    welcomeMessage: 'Welcome, ${fullName.toUpperCase()}!'.interpolate()
});

Much better!

Ember.String.interpolate does all the heavy lifting for you, setting up a ComputedProperty that observes all the properties you use inside the string.

Usage

Referencing a property inside the string is as simple as $propertyName. The dollar sign identifies it as a property that should be looked up and replaced.

Just like in language-level interpolation, expressions are supported by grouping the expression inside curly braces: ${expression}2

Another feature worth mentioning is that full property paths are supported, so this works:

// Full paths are supported: Welcome, BILBO BAGGINS!
example: 'Full paths are supported: $model.welcomeMessage'.interpolate()

Best of all, these really are computed properties so changing any property used by them will trigger them to update. In the examples above, if you changed the firstName property, all the interpolated strings would update to reflect it!

Summary

Ember.String.interpolate adds a huge improvement in code quality and speed for complex Ember projects. Get it here. Pull, fork, report issues and enjoy!


  1. Wish this were possible as well, but in practice…it's not. 

  2. Since interpolated expressions are evalulated JavaScript, be sure not to .interpolate() anything user-generated or you're risking security issues! 

Jan 13, 2013

The other day I was casually chatting it up with a fellow developer and the topic of obscure language features came up.1 Near the end of our friendly contest, I whipped out statement labels in JavaScript and won an expectedly puzzled look from him. Actually, statement labels have been around for close to half a century, in countless languages, but for now I'm just going to explain JavaScript's implementation.

Before I demonstrate, I'd like to note that you should avoid labels at all costs. Anyone who maintains your code will likely have no idea what they are and if they do, they'll hate you for using them.2

What Statement Labels Are

The syntax is quite simply:

label : statement

While the term statement label is rather self-descriptive, why you would use them may not be as evident.

Let's start with a simple example:

say_hello:alert("Hello!");

The function call alert has a label of say_hello. If we run this code as is, you'll see that it calls alert without any other action or fanfare. In this contrived case, the label was rather pointless.

A more useful demonstration requires you're familiar with all the valid statements. Assuming you're familiar, we'll go ahead and choose a while statement:

loop: while (condition) {
    /* Do stuff */
}

Since while loops allow an optional block, any statements inside this block are part of the overall while statement which our loop label references.

Now would be a good time to point out that labels are not variables and cannot be be referenced anywhere you use variables. In fact, there are only two ways you can reference them, which we'll see next.

Referencing The Labels

Now that we've got the general idea of how to assign a statement label, where can we use it? Two places, continue or break statements:

continue label;

// or 

break label;

Since most people associate these two with loops, let's talk about them first.

while (otherCondition) {
    /* Do stuff */
    if (totallyFinished) {
        break;
    }
}

You see this example above quite a bit, so why would adding a label help? Well...what do you do when you need to nest loops and, inside one of said loops, you need to break (or continue) from a parent loop?

while (condition) {
    /* Do stuff...now we need a nested loop */
    while (otherCondition) {
        /* Do nested stuff */
        if (totallyFinished) {
            /* Now we need to break out of the parent loop
             * but it's condition isn't finished! */
        }
    }
}

I've certainly seen people create variables that are just used to track state, something like:

var isDone = false;

while (condition && !isDone) {
    /* Do stuff...now we need a nested loop */
    while (otherCondition) {
        /* Do nested stuff */
        if (totallyFinished) {
            isDone = true;
            break;
        }
    }
}

And for most cases, I might argue that this is actually more readable, but this can certainly be resolved using labels.

outerLoop:
while (condition) {
    /* Do stuff...now we need a nested loop */
    while (otherCondition) {
        /* Do nested stuff */
        if (totallyFinished) {
            break outerLoop;
        }
    }
}

There's no limit to how many statements you label, so you could also give child loops their own and break out of them without breaking out of the parent, etc. Notice that I put the label and the while loop on separate lines, which is just an aesthetic choice.

Using Them With Blocks

Whether you realize it or not, you use JavaScript blocks all the time. That's the curly braces after if, for, while, etc.

var foo = "";

if (!foo) {
    // Any statements in here are "part" of this block
    foo += "hello";
    foo += " world";
}

Before you get too excited, there's one little gotcha: JavaScript does not have block scoping! In a nutshell, that means that anything you declare inside a block is visible to the nearest function scope or the global scope if not inside a function. This usually bites people coming from writing C/C++ and the like.

var foo = "yes";

{
    foo = "no";
}

(foo === "yes") === false;

This topic is well discussed elsewhere, so I won't get more into it, but be careful!

Because blocks are statements themselves, we can apply a label to them the same way we've done above.

my_awesome_block: {
    /* More statements  */
}

You can't use continue on a block label itself (as sort of a makeshift goto), but you can certainly break from them.

function sayHelloWorld() {
    scream: {
        alert("hello!");
        break scream;

        // Unreachable code
        alert("I will never be called!");
    }

    alert("world!");
}

Here's a more useful example where maybe you've got some predefined dataset that you need to iterate nested objects until you find one particular thing, then stop your deep searching.

function firstPersonWithSuffix(someGroups, letters) {
   var person = "", group;

   search: {
       for (var key in someGroups) {
           group = someGroups[key];

           for (var i = 0, len = group.length; i < len; i++) {
               person = group[i];

               if (person.indexOf(letters) === 0) {
                   // Breaking from a labelled loop prevents any further
                   // statements inside it from continuing, including these
                   // nested loops
                   break search;
               }
           }
       }

       // If reached, we didn't break our search so no one was found, but let's 
       // say this function CANNOT throw an exception or return null so we'll
       // return nobody, Unix style.
       person = "nobody";
   }

   /**
    * Now we still have a chance to run more statements.
    * Unlike if we would have just returned the match
    * immediately.
    */

    // Maybe we want to remove pre/post whitespace?
    person = person.trim(); 

   return person;
}


var people = {
   children: ["jim", "bob", "sarah"],
   adults: ["jessica", "fred", "john", "wilma", "nancy"]
};

firstPersonWithSuffix(people, "jo");

Conclusion

All things considered, I've never actually used labels in production code, even to solve nested loops. Why? Because I always found an easier, more efficient and certainly more maintainable way to solve the reason I thought I needed them. This is probably the reason few have heard of it, which is was a good thing up until this post.


  1. One of my biggest passions is programming language theory and compilers. If this gets you steamy too, sneak a peek at Titan, a language I'm working on. 

  2. Just because you (probably) shouldn't use something doesn't mean you shouldn't know how to use it! You'll come across labels somewhere eventually and the knowledge will pay off.