There have been several rumblings through the internet (blogs, tweets, etc.) about how they would implement types in JavaScript and how it would make JavaScript even faster and debugging even easier. Then a certain company went as far as to think about writing the next JavaScript language for the sole purpose to add Static Types and Classes. You can see that proposal here: http://www.dartlang.org.
I read through the specs on the new Dart language and for some odd reason, my blood started to boil. I don’t know why. I don’t own JavaScript. But it still bothered me all day. Why on earth are they creating a new language for something that can mostly be done now in JavaScript or can be done with a minor enhancement to it?
I have a whole separate rant on Class vs Prototypes. I’ll have to save that for another blog post. This post is about static types.
I don’t have an issue with wanting to put static types in a language. It makes for easier to debug apps and languages that can then run faster because there isn’t this whole type inference that needs to happen all the time. I generally despise untyped languages, and yet I love JavaScript. Go figure. During this post you’ll see my approach to solve the static type problem that is 100% backwards compatible (meaning it won’t cause a error in non-supporting compilers) and requires as little change to your development style as possible. However, as you see, this is no easy task nor is the solution as elegant as I would have liked.
So let’s play pretend: Let’s imagine if Brendan Eich called me one day (because in my imaginary world, Brendan has my number on speed dial when in reality, I don’t know him and vice versa) and said, “Dino, I have a problem and honestly, I just don’t have time to fix it. I’m the CTO of Mozilla, you know. People are complaining that JavaScript doesn’t have static types. Here’s what I need from you: Create a way to add static types to JavaScript that doesn’t break JavaScript / ECMAScript 5″.
My response would be, “Sure thing Brendan… I can do that. I’ll talk to you later. Hey, are you going to come over an roast some chestnuts this weekend? I just bought a bunch and this year’s harvest looks good!” (I love chestnuts. Grew up eating them around this time of year. It’s an Italian thing). Brendan would then respond, “Gee, I’d love to, but my private plane is in the shop. I’ll take a rain check. I’ll see you over the holidays and tell your wife and kids Happy Thanksgiving”. Or at least something like that… but I digress.
My first step was to write a few lines of JavaScript code.
var i = 0; |
Yeah, that’s about as far as I got when it dawned on me: Why do I need to do anything more? I already told the JavaScript compiler that I want to declare a variable i and I want it to be a number. Let’s see how it fits with other data types:
var i = 0; //i can only be assigned an Integer value. // Assigning a decimal value trims it to // an integer. var d = 0.0; //d can be assigned any numeric value. var s = ""; //s can be assigned a string var obj = {}; //obj can only be assigned an object, but // any object is fine. var obj = new MyObject(); //obj can only be assign an object that // passes the 'instanceof MyObject' test. var arr = []; //arr can only be assigned an arry var x; //Normal untyped JavaScript variable var x = null; //Normal untyped JavaScript variable var when = new Date(); //That's right, only a date object |
It’s mind shatteringly simple and it makes complete sense to any normal developer… or at least to one that thinks like me.
(NOTE: Every variable declaration above can be assigned the null value.)
Of course, I need to worry about all those people who for what every reason decided to declare a variable and initialize as one data type (not null, but an actual value) then to switch it’s type. Why on earth you would do that is beyond me and you deserve the hours of torture you will experience trying to track down your bugs. But I’m a nice guy (really, I am) and so I figured I’d leverage something introduced in ECMAScript 5: “use strict”. “use strict” forces a JavaScript compiler into a strict mode and stops certain bad practices from continuing forward. It tries to fix things that were not very well thought out when JS was just a baby. It’s great in that it’s also 100% backwards compatible and can be applied to a whole file, or just a block of code. Pure genius!
So here are some use case scenarios, since a lot of people need things spelled out for them:
//Use cases without "use strict"; var i = 0; //Declaring a variable and initializing it to 0 i = ""; //A WTF!?! moment for me, but JavaScript Say OK var obj = {}; //Declaring obj and assigning it an empty object obj = 99; //Again, WTF!?!, but JavaScript says OK. |
//Use cases with "use strict"; "use strict"; var i = 0; //Declaring a variable as an integer (set to 0) i = ""; //JavaScript TypeError i = 9.9; //OK, but i is assigned 9 i = null; //Still OK. var s = ""; //Declaring a variable as a string s = 9; //Nope. 9 isn't a string. TypeError //Assume MyObject is a function constructor var obj = {}; //Declaring obj as an Object obj = new MyObject(); //No problems obj = null; //Still OK obj = 3; //BUZZ: JavaScript TypeError //Assume MyOtherObject() is a function constructor //with the prototype of MyObject var objB = new MyObject(); //objB is a type of MyObject objB = {}; //BUZZ: JavaScript TypeError // {} instanceof MyObject failed objB = new MyOtherObject(); //Ding Ding Ding Ding. This // is OK because this passes // MyOtherObject instanceof MyObject |
Beautiful. So I write a short but elegant email and click send. I pat myself on the back and say,”Dino… you are so awesome.”. A few minutes later, Brendan replies to my email. I open it up expecting to be showered with praise. Instead, I find a single sentence: “That’s great… but what about function arguments?”.
Oh poop…
While my idea sounds great in a monolithic global scope, any developer worth a single penny would have at least one function. How is the compiler to know what static type is acceptable and how on earth could I have missed that?
Back to the drawing board… I’m keeping what I posted because it’s simple, elegant, and 100% backwards compatible. How do I incorporate function arguments to that? You can’t have:
function myFunction(arg1 = 0) { } |
That wouldn’t be backwards compatible. It has to be something that the old crappy compiler won’t break on and isn’t too much of a headache for developers to incorporate.
After a little bit of staring at the function declaration, I took a break and began writing some other code for another project. Here’s an excerpt:
/** * Creates an entity based on the entityType * @param {String} entityType the type of entity to load * @param {Object} [options] optional settings to pass to the entity */ function createEntity(entityType, options) { //Create an empty entity object options = options || {}; var entity = new Entity(options); //Load the entity information var loader = new JSONLoader(); loader.bind("complete", function(data) { data.render.container = document.getElementById("entities"); entity.addComponent("render", new RenderComponent(entity, data.render)); entity.addComponent("physics", _physicsManager.createComponent(entity, data.physics)); }); loader.load("data/" + entityType + ".json", false); return entity; } |
Huh… I thought. That’s interesting. In my JSDoc syntax is a way the JSDoc parser knows what type of parameter entityType is. I wonder if I could use that in my static type JavaScript enhancement. So this is what I can up with:
function myTypeSafeFunction(s /*String*/ , i /*Integer*/ , obj /*Object*/ , myObj /*MyObject*/) { // Yada Yada Yada... I'm really tired today. }; |
It’s not as pretty as I would have liked. By adding comments within the function declaration, we am now able to support static types in the function arguments. But I’m not thrilled with this implementation.
Then I thought about the function above some more. I noticed another common pattern I use in JavaScript to account for parameters being optional in functions. By optional, I mean when you call a function, you don’t have to specify every single parameter. If you only pass 1 parameter to a function that requires 2, the second one is assigned the ‘undefined’ value. A variable assigned an ‘undefined’ value is always evaluated to false in an binary-logic statement.
I then thought of how this could be applied to by function argument static type issue. Why not use this same idea in the compiler to determine a parameter’s type? With this approach the compiler scans the function for the common “x = x || ;” syntax. If it finds it, that it treats that parameter as a the type matching . See below.
function myTypeSafeFunction(s, i) { s = s || ""; //Compiler finds this and makes s a String i = s; //This is OK because i's type is never defined s = 23; //TypeError! } |
This approach requires very little change from the developer’s point of view. A check that their parameters are set is actually good practice! Also, the majority of the work is down by the compiler and not the developer. Ahh, I find this acceptable and Brendan should too.
So I package up my samples and send them off to Brendan. The next day, there is a ring at my door. It’s Lars Bak (Google’s V8 head), Larry Page and Sergey Brin (the founders of Google). Apparently, news of my awesome solution got out and they personally wanted to come over and thank me for solving this problem that Goggle was ready to dump millions in investing in a new language. In return, I get a few million in grant money to continue to being awesome and also a nice office located in Jamaica’s Montego Bay, right on the beach. (Again, this is all imaginary).
So that’s my first official not-a-the-standard-welcome-post post on my blog. I hoped you enjoyed it and have some insight into what kind of posts I will be writing in the future. Don’t know when or what it will be, but I’ll try to keep them light and funny and poke fun at myself whenever I can. After all, if you can’t make fun of yourself, then you are just taking life a bit too seriously.
Let me know your thoughts and feel free to comment below (registration required to protect the innocent).

