Wednesday, January 30, 2013

CoffeeScript prototypes and classes

CoffeeScript tries to overcome the verbosity of JavaScript's prototype and class syntax. Here's how JavaScript does it:

function foo(name){ = name;
} = function(){
    console.log('Status is fubar!');

o = new foo('John');;

That's a bit more of characters to type. If you take a look at how CoffeeScript does it:

foo = (@name) ->                 # the @name is same as writing = name

foo::bar = ->                    # the '::' is the prototype keyword
  console.log 'Status is fubar'
o = new foo('John')


But all this prototype business can be moved into a more object-oriented style using CoffeeScript's class constructs.
class Fish
  constructor: (@name) ->               # gets transformed into a simple JavaScript constructor
  swim: (direction) -> console.log @name + 'is swimming ' + direction # prototype; notice the @name which is
                                                                      # and the direction is a function parameter
fish = new Fish('Nemo')   # play around with fish object

I sort of subscribe to shorter code is cleaner code. That's why I'm liking CoffeeScript so far.

Sunday, January 27, 2013

CoffeeScript control structures

Coffeescript has really few control structures. Most of the loops, for example, can be written as comprehensions over arrays, objects and ranges. Comprehensions should be able to handle most places where you otherwise would use a loop, each/forEach, and map.

For example:
fruits = ['Apple', 'Orange', 'Banana', 'Grapes']
console.log fruit for fruit in fruits

Would result in this JavaScript:
var fruit, fruits, _i, _len;

fruits = ['Apple', 'Orange', 'Banana', 'Grapes'];

for (_i = 0, _len = fruits.length; _i < _len; _i++) {
  fruit = fruits[_i];

The real work happens at the console.log fruit for fruit in fruits line. It calls the console.log function for each fruit in fruits.

CoffeeScript also has a few cool tricks in working ranges. They are quite handy if you need row numbers for tables. Here is an example:

tableRowNum = (num for num in [10..1])  
console.log c for c in tableRowNum

The only real loop construct that CoffeeScript has is the while loop. But its better than JavaScript's because it can be used as an expression. It also works nicely with another keyword: the until keyword. For all intents is a while not loop in javascript.

# Econ 101
if this.studyingEconomics
  buy()  while supply > demand
  sell() until supply > demand

So far, CoffeeScript is surprising me. It's certainly not boring me.

Saturday, January 5, 2013

CoffeeScript data types and functions

CoffeeScript's golden rule is "It's just JavaScript". As seen, in the previous entry, it compiles to a 1-to-1 equivalent of JavaScript. This also means that CoffeeScript's data types are also limited to what JavaScript has. These are strings, numbers, booleans, arrays, objects, nulls and undefined values. But CoffeeScript has a couple of pretty cool stuff baked for data types, especially strings. Here is a pair of examples:

name = "Jay" // CoffeeScript doesn't need a var prefix 
greet = "Hello, #{name}" // String interpolation
                         // Result: Hello, Jay

grade = 88.43 
withHonors = 100 <= grade > 85 // chained comparisons
                               // Result: true

songNotes = ["do", "re", 
             "mi", "fa", 
             "so"] // just an array but CoffeeScript knows how to deal with new lines

Also, CoffeeScript takes care to make sure that all of your variables are properly declared within lexical scope — you never need to write var yourself.

There are a lot more cool/useless stuff baked into CoffeeScript variables but to really use them you need functions. In JavaScript, functions are needed for almost anything. Its the same in CoffeeScript. CoffeeScript just declares functions differently - more lisp/scala like.
// Here is a function without a paramter
foo -> alert('foobar')  // foo is the function name
                        // the part after the "->" is the body of the function

// Here is a function with a parameter
square = (x) -> x * x  

// Here is a function with default value on a parameter
fill = (container, liquid = "coffee") ->
  "Filling the #{container} with #{liquid}..."