Talks

CoffeeScript for the Rubyist

CoffeeScript for the Rubyist

by Mark Bates

In the presentation titled "CoffeeScript for the Rubyist," Mark Bates discusses CoffeeScript, a programming language that provides a Ruby-like abstraction on top of JavaScript, particularly within the Rails ecosystem. The talk aims to alleviate fears associated with CoffeeScript and promote its advantages as a front-end coding language that can be as enjoyable as Ruby is for back-end programming.

Key points discussed in the talk include:

  • Introduction to CoffeeScript: Mark introduces CoffeeScript as a small language that compiles down to JavaScript, allowing seamless integration with existing JavaScript environments.
  • Comparison with JavaScript: The differences between CoffeeScript and JavaScript are illustrated through examples, highlighting the enhanced readability and reduced boilerplate.
  • Syntax Differences: CoffeeScript employs an easier and cleaner syntax with no semicolons, fewer parentheses, and a focus on whitespace to define code blocks, which contrasts with JavaScript's more complex structure.
  • Ruby-like Features: Bates emphasizes CoffeeScript’s alignment with Ruby principles, showcasing features such as lambdas, default arguments, and ranges, making CoffeeScript familiar to Ruby developers.
  • Practical Coding Examples: Throughout the talk, several coding examples illustrate the simplicity of CoffeeScript syntax compared to JavaScript. For instance:
    • The use of succinct function definitions with the "stabby arrow".
    • Demonstrations of conditionals and object creation without excessive syntax.
    • The use of ranges and string interpolation akin to Ruby.
  • Enhanced Readability: The discussion emphasizes how CoffeeScript's concise syntax improves code readability and maintainability, making it easier for developers to manage.
  • Object-Oriented Features: Mark explains how CoffeeScript simplifies object-oriented programming, allowing for inheritance and easier class definitions compared to the verbose nature of JavaScript.
  • Context Binding: A clear explanation of how CoffeeScript handles context binding in callbacks is presented, which resolves common issues faced in JavaScript.

In conclusion, Mark Bates advocates for CoffeeScript as an evolution of JavaScript that enhances the developer experience by making code easier to write, read, and maintain, ultimately encouraging developers to embrace this new tool in their programming arsenal. He invites attendees to explore CoffeeScript as a valuable addition to their programming toolkit, especially for those already familiar with Ruby.

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.