WalkerCodeRanger.com

Month: February 2014

February 27, 2014

Why TypeScript Isn't the Answer

I previously wrote about the minefield that is JavaScript programming and several possible answers to the problem. One possible answer is TypeScript. It’s an OpenSource project from Microsoft and the language “is a typed superset of JavaScript that compiles to plain JavaScript”. It builds on JavaScript by adding classes, modules, interfaces and optional type declarations. When compiled, the type declarations are erased and ECMAScript 3 compatible code is generated. When possible, TypeScript tries to match syntax and semantics to proposals for ECMAScript 6. Some parts of those proposals are still very much in flux and it’s not clear what the final spec will be, so we’ll have to see how TypeScript is able to handle that.

Fixes the Wrong Problem

TypeScript enhances JavaScript with types, classes and interfaces. Some people think that is the problem with JavaScript. It’s not. The problem with JavaScript is not that it is a dynamically typed prototype based object-oriented language without classes. That is actually JavaScript’s strength. The problem is that it is a poorly designed language, filled with many hidden land mines awaiting the unsuspecting developer.

I think that JavaScript’s loose typing is one of its best features and that type checking is way overrated. TypeScript adds sweetness, but at a price. It is not a price I am willing to pay.

Who Maintains Type Definitions?

TypeScript adds optional type declarations, but when interacting with existing JavaScript libraries there are no type declarations and a lot of TypeScript’s benefits disappear. To deal with that, TypeScript supports type definition files. These are hand written files that provide the missing type declarations for an existing JavaScript library. Having good type definition files for the JavaScript libraries you want to use is an important part of having a good TypeScript experience. Microsoft points to the DefinitelyTyped project as the source of type definitions for popular JavaScript libraries. However, what happens when the library you want to use isn’t popular enough or is too new? Or, what if there are type definitions, but not for the particular version of the library you need to use? Have you actually looked at how frequently many of these JavaScript libraries release new versions? How can you be sure the definitions are correct? They are just one more source of potential development issues. Any such library add-ons are bound to be an additional source of headaches if they are not maintained by the library author. Even if you aren’t using typescript, you may have already experienced a problem like this in other projects with community maintained packages. Recently, I did when the NuGet packages for the somewhat new Ember.js library were out of date, and when the package for jQuery failed to correctly support side by side installs of the 1.x and 2.x code lines.

Still JavaScript

The real problem with TypeScript is contained in the statement that it is a “superset of JavaScript.” That means that all legal JavaScript programs are also legal typescript programs. TypeScript doesn’t fix anything in JavaScript beyond some things that were fixed in ECMA Script 5. So, for example, the non-strict equality operator == is still there and still has the shorter more natural syntax than the strict equality operator ===. There is still the strangeness of semicolon insertion. In some cases, the additional features actually make it more likely a developer will adopt the wrong mental model of the language semantics and walk right into a mine. Classes make the unchanged behaviour of the this keyword more confusing. For example, in a class like Greeter from the TypeScript playground, the use of this is confusing:

class Greeter {
	greeting: string;
	constructor(message: string) {
		this.greeting = message;
	}
	greet() {
		return "Hello, " + this.greeting;
	}
}

One can’t help but feel the this keyword in the methods of Greeter should always reference a Greeter instance. However, the semantics of this are unchanged from JavaScript:

var greeter = new Greeter("world");
var unbound = greeter.greet;
alert(unbound());

The above code displays “Hello, undefined” instead of the naively expected “Hello, world”.

Update
A commenter (alleycat5 on Reddit) pointed out that TypeScript partially addresses issues with == because it will produce type errors for comparisons with == when it has type information.

var a = "ssdf";
var b = 5;
alert(a==b); // "Operator '==' cannot be applied to types 'string' and 'number'."

However, if either variable has type Object or any it will not produce an error and continues to evaluate loose equality. For those not familiar with TypeScript, any is a special type that can be either an object or a primitive like a number etc.

Not the Answer

I conclude that TypeScript is not the answer. Or perhaps it’s more accurate to say it is the answer to a different problem. If you love JavaScript, warts and all, but wish it had classes, modules, interfaces and static typing then TypeScript is the answer. My prediction is that in time people will come to realize TypeScript doesn’t eliminate the JavaScript minefield and only makes it more confusing by providing the illusion of safety. TypeScript will become just another tool along the web development roadside used by a niche market of developers.

This article is Part 2 in a 6-Part Series.

February 20, 2014

The JavaScript Minefield

When I was starting out as a programmer, I learned and worked in C++. There weren’t that many options for Mac OS 7 development at the time. I had a copy of MetroWorks CodeWarrior. It sure beat MPW, which was Apple’s own development environment. For languages the choices were pretty much Pascal, C or C++. Perhaps Pascal would have been a better first language to learn, but that’s not what I picked. As I really learned C++ and began programming in it, I discovered that C++ is a very large and complex language. Why? Well, there are a number of reasons. One is that it follows the zero overhead principle, basically “What you don’t use, you don’t pay for.” That means every language feature has odd limitations and pitfalls to make sure it can be implemented in a very efficient way. Another is that, due to the focus on low level efficiency, there are no safety checks built into the language. So when you make a subtle mistake, which is easy given all the weird edge cases, the program compiles and silently does the wrong thing in a way that maybe succeeds 99% of the time but crashes horribly the remaining 1%. Finally, the language is designed for maximum power and flexibility; so it lets you do anything, even the things you shouldn’t do. This produces a programming minefield where at any moment one might be blown up by some obscure behaviour of the language. Because of that and because other developers and the standard library make use of every language feature, one must learn the whole language. However, C++ is so big and convoluted, learning it is really hard.

C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do, it blows your whole leg off.

The New Minefield, JavaScript

My days of C++ programming are long past. But of late, I’ve been spending more and more of my time in a new programming minefield, Javascript. When I first started out as a web developer in the early days of .NET web forms, we avoided JavaScript as much as possible. It was slow and plagued by browser differences. Now, JavaScript: The Good Parts and jQuery are in our rearview mirror and we have our sights set on JavaScript MV* frameworks like Ember.js, AngularJS, and Backbone.js. That means, whether we like it or not, we’ll be writing a whole lot of JavaScript. Many people are fully embracing JavaScript, bringing us tools like Node.js, RequireJS, Lineman and Grunt. Those are all great things, but they don’t change the fact that JavaScript is a minefield.

How is JavaScript a minefield? Well, JavaScript has all sorts of pitfalls lurking for the developer. Each pitfall is like a mine in the minefield, silently waiting for you to accidentally step on it. Just like the minefield, JavaScript’s mines are hidden in plain sight. Entire books have been written about all the mines present in JavaScript. Maybe I’ll get into what some of those are in future blog posts. Now, if you are going to venture into a minefield, you need a way to avoid stepping on a mine. You need either a safe path through the minefield or a detailed map of all the mine locations.

No Safe Path

Douglas Crockford was trying to provide a safe path through the JavaScript minefield when he wrote JavaScript: The Good Parts. He did an admirable job at laying out a subset of the language that was sufficient but avoided many of the mines. However, the problem with any safe path through a minefield is that if you ever stray from the path, it doesn’t help at all. Sometimes you need to stray from the path, as when you read/modify someone else’s code or use a third party library requiring other language features. Worse than that is when you accidentally stray off the path, something that is all too easy in JavaScript. That happens when, for example, you inadvertently use a variable without declaring it, even though Douglas Crockford warned you not to do that. So we see that, the safe path is sufficient for your first foray into the minefield, but not enough if you plan on really getting work done there.

When Maps Fail

Given that a safe path through the JavaScript minefield isn’t enough, it seems like we need a detailed map of the minefield. Many books and blogs have been written to provide that map. JavaScript: The Definitive Guide by David Flanagan is one of the most detailed of those books. The JavaScript Garden is a good place to start learning about the mines online. In a real minefield, a map would let you navigate safely, but at the cost of greatly slowing you down. In JavaScript, it becomes necessary to hold the complete “map” in your head while you are writing code. It’s just not possible to constantly be looking things up while coding. Also, you still need to remember when to look something up. The task of programming is already difficult enough as you try to juggle the problem domain and solution while expressing that to the computer without the added cognitive load of keeping the JavaScript minefield map in your head. I would say most people can’t do it, or at least can’t do it well. That is one of the primary reasons languages like Java and C# have beat out C++.

Furthermore, many of the JavaScript mines are easy to step on even when you know they’re there. For example, you might use a for in loop without checking hasOwnProperty because you mistakenly think that it is safe in your particular case. Beyond that, the human mind just isn’t set up to handle situations where things do not match their names. No matter how many times I tell myself that the this keyword doesn’t mean this, my brain still falls back into thinking of it that way. It’s as if someone put a sign reading “Cave Tour” over the bear den. When I’m busy talking to my friend, thinking about how hungry I am and trying to find the cave tour, I’m liable to walk into the bear den no matter how many times I was told the sign is wrong. The fault isn’t with me, it’s with the sign.

JavaScript History

So how did we end up in this JavaScript minefield? Well like a lot of minefields, it exists because of a lot of messy history. JavaScript was created in 10 days in May 1995 by Brendan Eich. He incorporated many great ideas from Scheme and prototype based object oriented languages. However, the syntax and certain other features of Java got tossed in too, and there were plenty of warts for better or worse. It’s just not possible to design a language in such a short time and get everything right. Since then, the language as evolved through a messy standardization process that was haunted by the browser wars. Today JavaScript is experiencing a renaissance, but it can’t escape from its history.

Can We Clear the Minefield?

So what are we to do about this JavaScript minefield if we aren’t prepared to just accept life in a minefield? Well, a lot of people have been working on that and trying to offer solutions. Those solutions fall into three categories, since hey, there is only so much you can do with a minefield. The three possibilities are:

  • Clear the minefield
  • Go to a different field
  • Build atop the minefield

The most direct approach would seem to be to actually clear the minefield by removing the mines. Unfortunately, in the case of JavaScript, that means actually changing the language. That is a very long and difficult proposition. None the less, that has been done some through the ECMAScript 5 standard, which fixed the fact that the developer could redefine undefined and NaN as well as adding strict mode to address other mines. Still, that isn’t enough for those who need to work in JavaScript now and the process doesn’t show any signs of clearing the minefield in the near future. Instead, it looks like ECMAScript 6 will just expand the minefield to encompass more area (to their credit, the new territory looks a lot better and safer than the old).

Then there is the approach of going to a different field. Unfortunately, there aren’t any good alternatives because JavaScript is the only language that runs in the browser. Various companies have attempted to solve this problem by providing plug-ins and other languages for the browser. There was Java applets and then Adobe Flash and more recently, Microsoft Silverlight brought .NET to the client. Before that, Microsoft had tried to create an alternative by putting VBScript into IE, but no one else jumped on board. Unfortunately, all of these haven’t succeeded in providing a truly cross-browser programming eco-system that developers could count on being installed on client computers. Most created a sandbox within the web page, rather than integrating with it like JavaScript. While all those technologies still exist, none of them is a serious contender for the future of rich web app development.

The last option is to build atop the minefield. This is where the minefield metaphor breaks down a little. But to push on, it is like building a deck over the minefield so that one can enjoy the nice view and safely walk above the mines without any risk of setting one off, even though they are still below you. One of the first important such technologies is GWT from Google. It provides a true Java to JavaScript cross compiler. Since then many different projects have appeared to provide cross compiling from various new and old languages into JavaScript. The asm.js project is even standardizing a subset of JavaScript as the target of such compilers. The rapidly growing support for source maps, which allow debugging of cross compiled languages in the browser, promises to significantly reduce the friction of using such tools. Currently, all the most promising technologies for solving the challenges of JavaScript fall into this final category.

Today, the three main contenders for superseding JavaScript are CoffeeScript, TypeScript and Dart. However, it’s not at all clear any of them will be able to dethrone JavaScript despite it being a minefield. In future posts, we’ll look at each of these three alternatives to JavaScript and whether we should adopt them or stay with JavaScript, perhaps with the aid of a tool like JSHint.

This article is Part 1 in a 6-Part Series.