00:00:05.920
Hello everyone.
00:00:25.359
Today, we're going to talk a little bit about CoffeeScript. I know DHH mentioned it earlier today as one of those things that a lot of people fear. I'm hoping we can take some of that fear, uncertainty, and doubt away today and replace it with fun. It's an awful pun, but we're going to try.
00:00:38.719
My name is Mark Bates, and I'm a consultant up in Boston.
00:00:43.760
I'm the author of "Distributed Programming with Ruby," which came out a few years ago. If you don't own it, you should because it's a really outdated tech book, and who doesn't want one of those? I'm also the author of "Programming in CoffeeScript," which is a really up-to-date tech book, and everybody should own one of those. You can find both these books available on book.markbates.com; the latter is available for pre-order and has been published as a rough cut on Safari today, so feel free to check it out as it's coming out in about a month's time.
00:01:12.560
Before we get started with CoffeeScript, let's have a very brief history lesson on JavaScript itself and how it came into being. Its birth is kind of interesting and explains a lot about the quirks that are present in JavaScript as a language.
00:01:30.799
Meet Brendan Eich, a developer for Mozilla back in 1995. He had a little mission: to create a language that would run inside the browser and allow developers, and more specifically himself, to change elements on the page and interact with the user. He decided he was going to make this really cool Lisp-style language.
00:01:42.720
He did, and he wrote this really cool Lisp-style language that no one has ever seen. The reason no one has ever seen it is due to one man. This man came into Brendan's office one day and said, "Look, Java is getting really popular. We need you to change this cool Lisp language, which no one's using anymore, into Java. We're going to give it a stupid name like JavaScript so people think they are somehow related, and it will become the bane of every developer's existence from that point on. Oh, and we need it in a week."
00:01:57.119
Because of those last couple of requirements—it needs to look like Java, sound like Java, and we need it in a week—we end up with this: JavaScript. This is actually a Backbone model in JavaScript. It looks very similar to Java. For those who have ever done Java, it's not a bad language. It's cool, but it has a little extra verboseness to it that I'm not particularly keen on.
00:02:07.119
But it works, and it does what it needs to. We have all lived with it all these years. However, times change, and things move on. If we fast forward about 15 years, we meet Jeremy. Jeremy is a developer at DocumentCloud and the lead developer on a little project called Backbone. For those of you who caught Sarah's talk, you know what Backbone is all about.
00:02:23.760
He also develops the Underscore library, which is kind of like ActiveSupport for JavaScript. Jeremy was sick and tired of writing his Backbone models like this. He thought there had to be a better way, and indeed there is.
00:02:36.240
So he took it upon himself to write CoffeeScript. Now, that same Backbone model looks like this in CoffeeScript. Jeremy is a happy man, and now I am a happy man, and I hope everybody here becomes happy as well.
00:02:44.720
So what is CoffeeScript? Well, CoffeeScript is a little language that compiles down to JavaScript. That's what the website says. It's an accurate description; while it may not be the most interesting, it's certainly accurate. It easily integrates with your current JavaScript environment, and the reason it does is that it ultimately compiles down to JavaScript.
00:02:57.760
So if you've thought about using CoffeeScript but weren't sure if you would like it, you can try it. If you don't like it—which you probably will—you can take that compiled JavaScript and just use that. There is zero loss here; you're not losing anything. It's not like you say, "I'm going to write my API server in Node, and if I don't like it, then I have to rewrite it in Ruby." You could say, "I'm going to try to write my front end in CoffeeScript, and if I don't like it, I can just use the JavaScript."
00:03:14.560
It's easier to read, write, maintain, and refactor—these are all wonderful selling points for developers. I find it interesting why there is so much fear surrounding this. It's a hybrid of Ruby and Python; I'm sure everybody in this room likes Ruby, but I'm not sure everyone in this room likes Python. That's okay! They only took a little bit of Python and a whole lot of Ruby to create CoffeeScript, and it's incredibly helpful.
00:03:24.760
What I mean by 'helpful' will become clear over the course of these slides. However, it's important to note what CoffeeScript is not. It is not magic, and it cannot do things that JavaScript can't already do. The big example I always give is 'method missing.' Everyone in this room should know what 'method missing' does in Ruby. It’s basically how Rails works; it's the core of Rails, but you can't do 'method missing' in JavaScript. I wish you could, but unfortunately, you can't.
00:03:44.960
This limitation means that you can't do 'method missing' in CoffeeScript either; it's just impossible. So this is what DHH was talking about earlier. He effectively stole the next two minutes of my speech today, and I'm a bit annoyed, but he because he elaborated on it so much better than I did.
00:04:02.880
People say this to me all the time: 'Well, I'm happy writing JavaScript. It's fine, it works for me. Why do I need to learn another language?' That's fine with me if you really want to be that way, but personally, I think it’s kind of a closed-minded opinion; a close-minded way to go through life. That's what DHH was talking about this morning—this conservative versus kind of liberal attitude towards learning new things.
00:04:35.840
Let's take a quick trip down memory lane again, and again DHH stole a little bit of material from me here today. Does anybody in the room know what this is? And I’ll give you a hint: it’s not COBOL. What is it? It's Assembly language.
00:04:44.960
Okay, great! Do you know what this code actually does? No, I don’t either. I took it from a website, but I think it spits out Fibonacci numbers. For a while, programs were actually written like this. They were also punched into punch cards and fed into big machines to run. People thought this was an acceptable way to work for a long time.
00:05:05.600
Then someone eventually said, 'That's ridiculous!' So they came up with C. I'm skipping a whole generation of languages here just to make a point. But anyways, here's C. I'm not a C guy; I’ve done a little bit of C, but I can look at this, and I know what's happening. This is much easier to write than Assembly language. A lot of great programs are written in this style today.
00:05:36.920
Everybody in this room has at least one device—whether it be a phone or a computer—that has some code like this. After some time, things progressed and someone said, 'You know, C is nice and all but has a lot of problems. I hate having to write header files. It's not really properly object-oriented, and I can't run it on all these different devices without recompiling.' So Java was born.
00:06:02.400
Here’s the Fibonacci sequence in Java. It's a little more succinct, but Java as a language is also quite verbose. You can write it once and run it nowhere—so the saying goes. And that is where I come into the picture. In 1998, I learned how to write Java.
00:06:20.320
I spent many, many years writing Java—too many years writing Java. In 2005, I was doing what most good developers do: I was drinking with some friends, and a friend mentioned, 'Have you checked out Ruby?' I said I had never heard of it. He told me it was a programming language, and there was this little framework bubbling up called Rails, which looked pretty sweet.
00:06:41.280
I was thinking, 'You know, I know Java. I've got my JSPs, my Servlets, my Struts, my Hibernate, my Ant builds. I have my IDE working, and I’ve got hundreds of thousands of lines of XML configuration—what do I need to learn something new for? It all works; it’s fantastic.' This is what DHH was referring to earlier.
00:06:56.720
Then I looked at Ruby, and I saw this syntax. I thought, 'Well, that looks nice!' Damn it, what the hell was I thinking? I wrote my first Rails app, and even though it sucked, it was amazing! I found it revolutionary; I didn't need to write all these XML files, and I didn’t have to deal with build scripts. Everything just worked.
00:07:10.160
Of course, back then I had to deal with deploying FCGI, but you know, it worked most of the time. It was much better. It was a significant improvement. Back then, I could write an app just as well in Java as I could in Ruby.
00:07:31.040
Nowadays, I couldn’t write an app in Java to save my life because I’ve done nothing but Ruby since 2005. But damn it, Ruby looks so much nicer to work with. It's easier to read, cleaner, and simpler. I can debug it easier, maintain it easier, and people coming onto a project can look at it and understand what it’s doing easily. It’s easier to refactor overall—it’s just a better way to be.
00:08:06.080
The same goes for CoffeeScript. It's an evolution of what JavaScript is. It's like taking Java to Ruby and JavaScript to CoffeeScript. It transforms the way you look at these languages; it really is wonderful. At the end of the day, it’s a new way of writing bytecode.
00:08:31.440
So let's actually jump in and start looking at some CoffeeScript.
00:08:35.920
There's going to be a lot of code over the next 30 minutes, so I will post all these slides later if you can't see all the code. Hopefully, the font will be large enough, and it will work.
00:08:56.640
Let's start with the syntax, which is what everybody talks about with CoffeeScript. Everyone thinks that syntax is CoffeeScript; however, it's much more than just syntax. Here's an example of a side-by-side comparison of the exact same code. On the left, we have our JavaScript AJAX jQuery function, and on the right, we have the exact same CoffeeScript equivalent.
00:09:12.560
No semicolons, no curly braces, very few parentheses—nice white space. The white space is evident in our JavaScript, and we’ll get to that in a minute. There are no extra keywords like 'function' overall, making it a little simpler and easier to focus on.
00:09:32.320
If I look at this code on the right, my eye is drawn immediately to the actual code and not to all the semicolons and curly braces that surround it. The syntax rules are very simple, really: there are no semicolons ever!
00:09:42.080
There’s no debate in the CoffeeScript world about whether you should have semicolons. There's no big-long blog post or Hacker News articles with people screaming at each other. If you put a semicolon in, the compiler’s gonna kick it out and yell at you.
00:09:56.919
There are also no curly braces. Now, there’s a small asterisk to that, as there are occasional times when you need to use curly braces, but when discussing syntax and defining closures and functions, curly braces are gone. There's no 'function' keyword—you don't need it.
00:10:06.240
Some other keywords that are absent include 'with,' which is an unfortunate thing to do in JavaScript anyway. There are relaxed parentheses rules, very similar to Ruby's relaxed parentheses.
00:10:17.920
And yes, white space is significant in formatting—it will affect how your code is read and executed. Let's take a moment to look at these parentheses rules.
00:10:40.960
On the left, we have three different types of functions we're creating in CoffeeScript. I'll talk more about functions in detail in a few minutes. The way to define a function in CoffeeScript is with the 'stabby arrow' (the dash-arrow).
00:10:50.720
Here, I'm creating 'no arg1', which is a function that takes no arguments; 'no arg2' works the same way, and 'with arg' down at the bottom takes one argument into the function. When defining a function that has no arguments, you need not use parentheses—it's as simple as that.
00:11:12.080
If you're defining a function that requires arguments, parentheses are required—pretty simple rules. However, when it comes to calling functions, the rules do get a little messy.
00:11:28.720
If you're calling a function that has no arguments, you need parentheses. But if you're calling a function that has arguments, you don’t need to use parentheses. I generally err on the side of using parentheses, as I find it a little cleaner.
00:11:49.840
I'm against the Seattle-style Ruby code, and for the style of CoffeeScript, using parentheses saves a lot of hassle down the line because it's easy to trick the compiler into thinking you're doing something you didn't mean to do if you forgot the parentheses.
00:12:02.760
If we look at this little code example, that's the JavaScript, in case you’re wondering. Here's an example where the parentheses rules led me astray: I wanted to find a particular DOM element in jQuery and call the text function on it.
00:12:16.240
If I don’t put the parentheses there, it actually calls the text function on the string as opposed to the jQuery object. Thus, in this case, the parentheses are kind of required for the order of precedence.
00:12:29.440
If you’re not sure what to do, just go ahead and put the parentheses in. No one's going to yell at you. Now, let’s talk about white space. I get the white space argument a lot for some reason, and I don't know why people complain to me about that.
00:12:53.760
They say, 'I don’t want to use significant white space. I think it’s stupid and I don’t understand it.' To them, I ask, 'Do you write your code like this or like this?' If you do, you're kind of difficult to work with. Honestly, I don’t want to work with you.
00:13:12.280
This coding style is almost impossible to read. You can decipher it, but it’s really hard, and then when you want to refactor it, it becomes confusing to determine which block each line belongs to, and where these curly braces end.
00:13:38.360
This is not good code. Now if you're writing code like this, take a minute to indent it properly. When properly formatted, it’s going to look like this, which is much easier to read and manage.
00:13:56.560
So CoffeeScript is trying to impose a nice development style on you too. It's trying to say, 'Hey, be a better developer. Be a nicer person in your community by ensuring you write your code in a nicely formatted way.' By doing this, they’re embedding it into the language just like Python did.
00:14:16.080
For those who are curious, I personally think CoffeeScript should have been called RubyScript at some point because it looks and feels so much like Ruby. In fact, I have accidentally written stuff in both languages that was incorrect. Let's look at some of these things, starting with conditionals.
00:14:43.680
Here's how you do conditionals in CoffeeScript: there is no 'end' keyword. We simply use the signature white space to define when the block of code is over. We can do inline conditionals just like we can in Ruby, so we can say 'do something if true' or 'do something unless true.' The 'unless' keyword is there as well.
00:14:56.700
And at the end of the day, that's just being compiled down to a bang! unless you know if bang true—just like it does in Ruby. But it's nice to have this option as it makes your code a little more readable. Now let's discuss objects and hashes.
00:15:28.320
Here’s a case where my earlier point about curly braces comes into play. CoffeeScript allows for several ways to define an object. The first is a single-line notation, which requires curly braces. Or you can use a multi-line format, which is the second option I’ve shown here, and it’s the one I use most of the time.
00:15:44.960
This is because it reads nicely and is easier to expand. In the multi-line format, you don't need curly braces or commas because the new lines and indentation tell the compiler what belongs to the object.
00:16:04.400
This feature helps in avoiding simple mistakes like forgetting a comma. You can also do if statements while building this object inline.
00:16:23.839
When passing an object into a function, you can do so using the Ruby-style without needing curly braces. You can just pass in key-value pairs directly, though you would need curly braces if you wanted to pass multiple sets of objects.
00:16:40.960
Here’s the JavaScript output you would expect. You can see that both styles from the first two examples look almost identical. It really comes down to personal preference; I prefer the multi-line object syntax—it looks very clean.
00:16:55.120
Moving on to ranges. We all know what ranges are in Ruby, and you can do them in CoffeeScript too. On the left, you have the CoffeeScript, and on the right, the JavaScript output. Something interesting to note: when I use '1 to 5', it builds the appropriate array in JavaScript, but when I use '1 to 100', it actually constructs an array.
00:17:23.360
It's not going to build a massive block of JavaScript to list all the numbers up to 100. For those curious about the crossover point, where it shifts from the 'a b' style to the 'c d' style, it's 22. I have no idea why, but I tested it one day.
00:17:38.560
String interpolation. It's not the most exciting topic, but it's very useful in JavaScript. It follows the same rules as Ruby, where double quotes are interpolated, and single quotes are literals.
00:17:51.680
In this case, I'm building a bunch of HTML using triple double quotes or triple single quotes for multi-line strings. This is great if you’ve ever built an input tag in JavaScript.
00:18:06.640
Raise your hand if you've ever forgotten to escape a single or double quote when concatenating strings. Exactly—what a pain! You won't need to do that anymore because now you can build a nicely formatted string right in there.
00:18:21.680
Now let’s talk about functions. I mentioned I would touch on functions a bit. This is an example of a function in CoffeeScript where we define a variable 'p' that is set to this function, which will take an argument named 'name.' That arrow defines that everything following will be part of my function.
00:18:43.440
Here, we just log 'Hello, hello RailsConf 2012.' I could have omitted the parentheses when calling that function, but I generally include them because I think it looks nicer. However, I tend to forget to add them for console.log.
00:19:03.280
Here's the JavaScript output of that function. When I first started using CoffeeScript, this syntax was a bit tricky for me to grasp; something about it just seemed weird. Eventually, I realized the arrow points toward the code doing the work.
00:19:16.800
What is even more familiar is that this syntax resembles the Ruby 1.9 syntax for lambdas—it's essentially a reverse of the argument list. The Ruby version is actually more verbose than the CoffeeScript version because it requires those extra curly braces.
00:19:35.680
Next, default arguments! We love default arguments in Ruby, and everyone utilizes them in Rails. Now we can also use them in CoffeeScript. For example, I have a 'create element' function that takes a name and an optional list of attributes, setting it to an empty hash by default.
00:20:00.200
Here's what that JavaScript ends up looking like. It's simple to build that functionality in CoffeeScript compared to the equivalent boilerplate code in JavaScript. Using CoffeeScript makes your life much better.
00:20:15.440
Let's discuss splats. We can use splats in CoffeeScript. The syntax is much nicer, using the ellipsis. You can define a function such as 'first, second, others' which signifies that your 'others' parameter is an array containing anything beyond those first two arguments.
00:20:35.840
JavaScript, on the other hand, doesn't do this for you by default, requiring a lot of boilerplate code to achieve the same functionality. Many developers tell me they cannot onboard new programmers easily, arguing their lack of familiarity with CoffeeScript.
00:21:02.920
However, I believe this four-line version is easier to read compared to the longer version. It’s also straightforward to capture output of a for loop into another object, enabling you to process items conditionally.
00:21:21.440
Now this is where things start getting interesting. You can wrap everything discussed in simple, easy-to-use classes with CoffeeScript. The three lines here demonstrate a valid CoffeeScript class definition, where I've created a class called 'Employee'.
00:21:43.840
In one line, I create a new instance of that employee class, allowing me to set attributes on that instance. JavaScript lacks proper class functionality; it can create instances of functions, but CoffeeScript takes care of the boilerplate code associated with it.
00:22:20.480
We can add functions to our CoffeeScript constructor function, which will be called every time a new object is initialized. Here's an example with a salary function for a well-paid developer.
00:22:42.960
This slide contains one of my favorite one-character features in CoffeeScript. In my mind, there are three single-character shortcuts that make it worthwhile. I’ll show you the first one: it involves the '@' sign.
00:23:09.440
The '@' represents the instance variable. It works the same way in CoffeeScript, replacing the 'this.' syntax in JavaScript. So if you define 'at options.salary', it equals 'this.salary' without the repetitive boilerplate.
00:23:30.720
Look at the salary function; you can see we are assigning 'at options' instead of plain 'options', meaning that CoffeeScript is setting the instance variable directly.
00:23:48.880
This slide has another feature: the question mark '=' operator. This allows you to set defaults for variables if they’re null or undefined. Essentially, it checks if the value exists and assigns it if not.
00:24:00.920
We can extend classes with CoffeeScript, introducing inheritance. For example, the Manager class can inherit from Employee. In the constructor, I’ll call 'super', which works the same way as Ruby, passing arguments when necessary.
00:24:40.080
If I create a new Manager instance and invoke its salary method, it will return the salary defined in its class. Here's what that JavaScript code looks like.
00:25:00.960
Now, let’s explore bound functions. This concept often confuses new CoffeeScript developers. I’d like to assume that most of you have worked with AJAX before. When using AJAX calls, you pass in callbacks and may run into issues with context.
00:25:22.480
In this example, we’re dealing with a User class that constructs a new user by taking a 'name' argument, and the 'say hi' function greets that name. When we create instances 'bob' and 'mary', we pass their 'say hi' functions.
00:25:44.160
We expect to see the expected greetings being logged, but we actually see 'hello undefined'. This issue arises due to JavaScript losing the context of 'this'. In this case, we need a way to bind the context properly.
00:26:05.200
Here’s where the magic of CoffeeScript shines through. With one character change—the fat arrow in CoffeeScript—we retain the context correctly.
00:26:18.760
Let me show this again to emphasize: the change from the dash arrow to the fat arrow means we bind the context appropriately, so we’re able to greet Bob and Mary correctly.
00:26:34.880
Here's a simpler version without all the log things going on, showing that JavaScript ultimately defines everything correctly. It effectively binds the functions upon creating the instance, linking the context properly.
00:26:49.600
Lastly, let's talk about the existential operator. This helps check if a value exists before trying to use it. For example, in this code snippet, 'foo' is checked for existence before being logged.
00:27:05.840
This ensures that if 'foo' is undefined or null, the code won't run; this operator is valuable for preventing errors on security checks.
00:27:24.000
Moreover, we can chain these operators together. If we have a current user with a first name that exists, then we can print it out. We can do this repeatedly, meaning CoffeeScript helps simplify safe checks, leading to cleaner code.
00:27:47.920
Here's how the generated JavaScript looks. This method operates similarly to the 'try' function in ActiveSupport, but CoffeeScript's way of chaining these operators makes it genuinely convenient.
00:28:03.440
With that said, I’m winding down here a little bit. There are some things I didn’t cover, such as scoping, security, and strict mode. CoffeeScript automatically compiles your code into strict mode, offering early debugging and error reporting.
00:28:24.320
It fixes common mistakes like confusing triple equals with double equals. Furthermore, it provides great operators—for example, the existential operator I showed you.
00:29:06.720
There's also the 'do' keyword for asynchronous loops, which aids in context preservation. There are countless features to explore, so if you're interested, I recommend you buy my book, 'Programming in CoffeeScript'.
00:29:25.360
You can also follow me on Twitter @markbates. Thank you for your attention, and I’m happy to take any questions.
00:29:36.320
Thank you.
00:38:27.280
Goodbye.