Composing objects - Composition - CoffeeScript in Action (2014)

CoffeeScript in Action (2014)

Part 2. Composition

Having learned how to use CoffeeScript, you’ll now learn how to use CoffeeScript well. Using a language well means learning how to effectively compose programs, so this part of the book is about learning to express your programs at a higher level and about learning some more advanced idioms that will make your programs easier to write and to comprehend.

Because learning to do things well requires dealing with challenges, some of the topics covered later in this part will require closer reading, and the examples may require more experimentation. To provide you with context for these topics, some of the listings need to be quite long. Take some time to absorb them.

Chapter 5. Composing objects

· Structuring code with classes and inheritance

· Using prototypes for dynamic flexibility

· Extending your program with mixins

In the previous chapter you traveled the road from object literals to prototypes and then classes. Along the way you started to build an understanding of how objects work in CoffeeScript. Now it’s time to reverse course by first defining some classes of your own and then slowly taking them apart to see the objects and prototypes that underpin them. This will give you the complete picture of objects in CoffeeScript.

You’ll begin the exploration with classical objects and class inheritance, followed by methods and other class properties and an explanation of the super keyword. Then you’ll learn how to modify objects, classes, and prototypes. Finally, this chapter ends by teaching you what mixins are and how to use them. The flexible syntax and object model of CoffeeScript make writing mixins elegant, even though they’re not a built-in language feature. First up, classes and classical objects.

5.1. Being classical

Although objects in CoffeeScript are fundamentally prototype-based, the prototype-based approach that you learned about in chapter 4 is uncommon in programming languages. The class-based approach, where objects are created using classes, is common. So if classes are common, they must be good for something, right? Yes, they are. Classes are natural and convenient for declaring common properties and methods to be shared by multiple objects.

As you saw in the previous chapter, CoffeeScript provides the convenience of classes by providing class syntax on top of objects and prototypes. How does CoffeeScript do that and what are the trade-offs? Read on to find out.

5.1.1. Raw data

Imagine that Agtron wants to open an online shop to sell digital cameras. Unsurprisingly, he has asked you to write the program to do that. Figure 5.1 demonstrates the shop homepage that he wants.

Figure 5.1. Agtron’s shop homepage

Where to start? To sell the cameras, you’ll need to know which cameras to sell and how many are in stock. Sample data containing this information has been supplied to you as an object:

data =

X100:

description: "A really cool camera"

stock: 5

X1:

description: "An awesome camera"

stock: 6

The sample data has information for two cameras, an X100 and an X1. Each camera has a description and a stock count. Sure, the data could be used in a program without any classes, but classes buy you an abstraction by separating your data from your program.

5.1.2. Class abstractions

To learn why classes are useful, start without any abstraction and see what happens. Take the camera data and display each camera as a string suitable for display on the web page:

"X100: a camera (5 in stock)"

Then create an array of these strings using a comprehension (see section 4.3 if you need a refresher on comprehensions):

for own name, info of data

"#{name}: #{info.description} (#{info.stock} in stock)"

# ["X100: A really cool camera (5 in stock)",

# "X1: An awesome camera (6 in stock)"]

Now imagine that Agtron wants users to purchase cameras by clicking them. Modify the comprehension to create an element in the document, add the camera data, and then add a click handler. Doing this in a web browser looks like the following (note that the following example does not work in your REPL):

This is getting more complicated: there are more things for your brain to keep track of and more things for you to worry about. Regardless, you can struggle through, so far.

Now suppose Agtron also wants the stock counts to be updated after each purchase request. What will you do? Add some more lines to the comprehension and make it harder to understand? No. As a program grows, instead of piling junk upon junk, you require more abstractions to help you manage things. Time to try classes.

A camera class describes how cameras work. In your program, camera objects are created, rendered onto a web page, and purchased. The following listing shows a Camera class with a constructor for creating cameras, a render method, and a purchase method.

Listing 5.1. A simple Camera class

The new keyword in front of a class name invokes the class constructor. When a constructor is invoked with the new keyword, an object is created and given to the constructor, where you can access it using the @ symbol. When you new a Camera,

x1 = new Camera 'X1', {

description: 'An awesome camera', stock: 5

}

the object returned has name and info properties assigned to it by the constructor:

x1.name

#'X1'

x1.info

#{description: "An awesome camera", stock: 5}

The object returned also has the methods, such as render, from the class declaration:

x1.render()

# "Camera: X1: An Awesome camera (5)"

It’s worth reiterating at this point that a method in CoffeeScript is really just a property containing a function. Evaluate it and see:

x1.render

# [Function]

Evaluating a method name without invoking it will produce the function value itself.

Private or public?

Many object-oriented languages divide object methods into those that are private and those that are public (and sometimes other options such as privileged). The JavaScript object model has only public properties. To hide information in JavaScript, you need to use function scope.

You now have a description of how cameras work. How about the other things in the program? The shop is more than cameras. The shop receives all of the camera data and uses it to create all of the camera objects. The Shop class is a place to declare the shop behavior. Remember, when you plan to have many objects with the same behavior, a class is a convenient place to describe that behavior

with the sample data that you have:

Now, create a new shop by invoking the constructor with the data:

shop = new Shop data

You have two instances of the Camera class—both created by the Shop constructor. What does this look like in the context of a real program? In listing 5.2 the Camera and Shop classes are fleshed out to implement the first version of the online shop.

Important: how to run the listings

Listings 5.2, 5.3, 5.4, 5.5, 5.8, 5.10, and 5.11 demonstrate different object-based techniques in CoffeeScript using a small client-side program. The final listing, 5.13, is a small server-side program intended to run each of these different listings. To experiment with the code in the listings, invoke listing 5.13 from the command line with the listing number for the client-side program:

Any changes you make to the listings will be automatically reflected in the client script delivered to the browser. So if you make a change to a client-side script and refresh the browser window, you’ll see the result of your changes.

In the next listing the Shop class fetches raw JSON (see section 4.4.1) from a remote server and uses it to create cameras. The http and get functions use some browser APIs that you need not be familiar with here. Experiment with the listing to understand how the application fits together.

Listing 5.2. Agtron’s camera shop client application (version 1)

In the Camera and Shop classes, this program has clear descriptions for the behavior of products and shops.

As the program grows, you’ll find that you have different classes of similar objects and that you’re duplicating methods across different classes. How will you deal with this? One technique is class inheritance.

5.2. Class inheritance

In class-based object-oriented languages, the most common technique for organizing classes of objects with some things in common is called class inheritance. But CoffeeScript isn’t a traditional class-based language. It’s a prototype-based language where objects inherit properties from their prototype (see chapter 4 if you need a refresher on prototypes). If CoffeeScript isn’t a class-based language, can you do class-based inheritance? Yes, by using the extends keyword.

5.2.1. extends

Imagine now that Agtron wants to sell more than cameras. He also wants to sell skateboards. Cameras and skateboards are different, so you can’t use the same class for both of them. You could copy and paste the Camera class, rename a few things to create a Skateboard class, and then modify the Camera class to add a megapixel count. You could, but you don’t. Instead you use extends.

Declaring extends

Given that cameras and skateboards are different products, you define a Product class:

class Product

Cameras and skateboards can be defined as products by saying their classes extend the Product class:

class Camera extends Product

class Robot extends Product

class Skateboard extends Product

The keyword extends in a class declaration means what it says. If the Product class is declared with a purchase method and the Skateboard class extends it,

when you new a Skateboard, it has a render method:

skateOMatic = new Skateboard "Skate-o-matic", {

description: "It's a skateboard"

stock: 1

}

skateOMatic.render()

# Skate-o-matic: "It\'s a skateboard (1 in stock)"

Now that you have a Product class, you can modify Camera without affecting skateboards or anything else that extends a product. Add a mexapixels method in the class declaration for Camera:

When you create a camera and a skateboard, the camera has a megapixels method but the skateboard does not:

x11 = new Camera "x11", {

description: "The future of photography",

stock: 4,

megapixels: 20

}

sk8orama = new Skateboard "Sk8orama", {

description: "A trendy skateboard",

stock: 4

}

x11.megapixels?

# true

x11.megapixels()

# 20

sk8orama.megapixels?

# false

If CoffeeScript is not class-based, how does it do class inheritance? It’s all in the compiler, and classes in CoffeeScript are just syntax. They are syntactic sugar for the prototype-based objects underneath. Something is called syntactic sugar when it makes it a bit easier or sweeter for a specific thing in a programming language. Many people, including Scruffy in figure 5.2, have tried to add classes in JavaScript without any syntactic sugar. None of them caught on very much. Without sugar they’re unpalatable.

Figure 5.2. Sometimes you need a little sugar.

The syntactic sugar CoffeeScript provides for classes makes it easier to write classes in a language that’s really prototype-based.

5.2.2. How does it work?

At this point you may expect a side-by-side comparison of CoffeeScript class syntax with the compiled JavaScript to show you what’s going on. In this case, though, the raw JavaScript actually confuses the matter, so it’s too early to think about the compiler. Instead of looking at everything the compiler does, consider a product object:

product =

render: ->

purchase: ->

This product object has two properties. How do you make lots of them? With a function.

You have two things: a prototypical product and a function that constructs product objects. A class declaration achieves the same thing in a different way:

How does extends fit into this picture? Suppose you took the earlier product object (not the class) and created a new object from it:

camera = Object.create product

camera.megapixels = ->

Now if you use construct on this camera object, you can create other camera objects:

x11 = construct camera, '', stock: 6

This x11 object inherits from camera, which in turn inherits from product. The extends keyword in a class declaration works in much the same way. It makes the prototype of one class inherit from the prototype for another class. The way that an object inherits from a prototype object that in turn inherits from another prototype is commonly referred to as the prototype chain.

In listing 5.3 the client application from listing 5.2 has been enhanced with an inheritance hierarchy using extends. To create objects from different classes, the Shop constructor has been modified to look at the data source and to new the appropriate class. Parts of the full program that are identical to listing 5.2 have been omitted from this listing.

Listing 5.3. Agtron’s shop client application with multiple product categories

You’ve now extended a class to share some behavior and keep some other behavior distinct using class inheritance. When working with classes, though, there are times when you have behavior that’s related to a class of objects but belongs to the class itself. Declaring these behaviors is simple to do in CoffeeScript. You’re about to find out how.

5.3. Class variables and properties

So far all of the properties you’ve defined with classes belong to instances of classes. This means they’re properties found on instances of the class:

Some properties don’t make sense as instances of the class. Some properties make more sense as properties of the class itself. Imagine all of the products sold in Agtron’s shop are faulty and need to be recalled. It’s easy to invoke recall on the Product class:

Product.recall()

It’s not so easy to hunt down all of the products ever constructed and invoke recall on each one. You might argue that it more accurately reflects the real world for things like product recalls to be much more complicated, but you like simplicity. Class properties can be a simple and useful technique.

These are Class Methods, Right?

Class properties in CoffeeScript can serve similar purposes to class methods in Ruby, Smalltalk, or Objective-C and even static methods in Java or C++.

5.3.1. Usage

Imagine now that Agtron wants a product search feature on his website so that people can find products by name. When a user searches for shark repellant, they should be shown a list of all shark repellant products that Agtron has for sale. The search feature will have an input field where users can enter a search term. Agtron’s design for the new homepage is shown in figure 5.3.

Figure 5.3. Agtron’s shop with product search

In order to find a specific product, you need to keep a reference to each of the product objects. An array of objects does this nicely. Each object in the array has a name property and corresponding value:

Here’s a crude brute-force find function for this array:

find = (query) ->

(product for product in products when product.name is query)

Use this find function by calling it with a product name:

find "Duct tape"

# [ { name: 'Duct tape' } ]

The products you already have in the client code for Agtron’s shop are objects with name properties, so a similar find function will work. But you do not yet have an array of all the products created. Where should the array of product references go? How about in the Shop constructor?

class Shop

constructor: (data) ->

products = []

for own name, info of data

products.push new Product(name, info)

But that assumes that an instance of the Shop class creates every instance of Product. Awesome, until somebody news a Product outside of the shop and it’s never found. Given that find is about products, why not put it on the Product class?

Product.find('Pixelmator-X21')

# [ Camera { name="Pixelmator-X21", info={...} } ]

The Product class can have a property like an object because it is an object.

Class methods

Any class is an object and has properties just like any other object. To specify a class method named find, just assign a function as the find property directly on the class:

Product.find = (query) ->

(product for product in products when product.name is query)

For that to work you need somewhere to define the product variable. You don’t want an evil global variable; you want a variable that lives with the Product class. You want a class variable.

Class variables

All variables are function-scoped so you’re surprised to see what happens when a new variable is assigned in the body of a class declaration:

Class variables are scoped to the class body. The class body has a variable scope like a function (as you’ll see later, when compiled to JavaScript the class declaration really is a function). They look a little bit like instance properties; be careful to notice the distinction.

Class variables vs. instance properties

Variables always use the = operator, whereas object properties use the : operator:

Methods can access class variables because they’re inside the class declaration with them:

You now have a place to keep the product variable inside the Product class. Unfortunately, that also also makes it invisible to your Product.find class method:

The find method is not declared inside the class. The class body has a function scope, so the find method must be defined inside it in order to see the product variable. How do you define it inside the class body so that all the things related to the class are defined in one place?

5.3.2. Declaring (to keep things together)

Inside a constructor, @ refers to the new object being constructed. Inside an instance method, @ refers to the instance by default. That much you know. Directly inside the class declaration, @ refers to the class itself. The @ keyword is used to define the find property on the Product class:

Remember that @ is dynamic; the object it refers to depends on how the function is invoked. Inside the class body the class body itself has been invoked. Yes, the class body works like a function. It’s still too soon to see why, and besides you now have a solution for Product.find:

Now, by using a class variable and a class method, you have a solution that finds a product:

new Product "Green", {}

Product.find 'Green'

# [ { name: 'Green' } ]

It’s time to tie this back to the overall shop program. A new version of the client application, this time with the Product.find, is in listing 5.4. An input field has been added to the HTML document, which provides an interface for users to enter the name of the product they want to find. As with previous listings, some functions and methods that are identical to earlier listings are omitted. The following listing can be run using listing 5.13.

Listing 5.4. Agtron’s shop client application with find

Notice that some parts of the program are becoming a bit difficult to follow. The view (which manipulates things displayed in the browser) takes up a lot of room in the program and obscures the other parts of the program. There’s a way to move those parts of the code somewhere else where they won’t get in the way, and you will learn about it later in the chapter. Before moving on, though, there’s one more thing you need to know about class properties.

Class property inheritance

If a Product class has an existing find method, then a Camera class that extends Product will inherit that existing find method:

products = [

name: "Shark repellant"

,

name: "Duct tape"

]

class Product

Product.find = (query) ->

(product for product in products when product.name is query)

class Camera extends Product

Camera.find?

# true

Add a class property to Product dynamically after Camera has already extended Product. The Camera class doesn’t get the class property:

class Product

class Camera extends Product

Product.find = (what) -> "#{what} not found"

Product.find?

# true

Camera.find?

# false

The class declaration isn’t dynamic. To modify a class at runtime, you need to start thinking in prototypes.

5.3.3. Exercise

Write a Camera.alphabetical class method that returns an array of all the cameras sorted alphabetically by name.

So far in this chapter you’ve declared and extended classes and added properties and methods to both instances and classes. In some cases, though, you don’t simply want to add behavior—you want to change it. To do this you need to know what happens when you redefine something that you’ve inherited and how to get back the original after you’ve redefined it.

5.4. Overriding and super

You can change the property of an object any time, just by assigning something to it. What about a class, though? Assigning a new value to a class property works the same as any object:

class Human

Human.rights = ['Life', 'Liberty', 'the pursuit of happiness']

Human.rights

# ['Life', 'Liberty', 'the pursuit of happiness']

Human.rights = Human.rights.concat ['To party']

Human.rights

# ['Life', 'Liberty', 'the pursuit of happiness', 'To party']

Class methods are just properties on a class. How about instance methods? What happens when you write a class declaration that defines an instance method that’s already inherited from another class through extends?

5.4.1. Overriding

Imagine now that Agtron wants cameras to look different than other products on the shop website. He wants them to have a photo gallery next to their product description. The Gallery class has a constructor and a render method:

class Gallery

constructor: ->

render: ->

Using the constructor, a new gallery is created with each new camera:

class Camera

constructor: ->

@gallery = new Gallery

When the camera renders, it will need to invoke the render method on the gallery. This means the Camera class needs a different render method from other products. Put this method inside the class declaration:

The constructor and the render method have both been overridden:

To override a method that you got from extending a class, declare a new version in the new class. Sounds too easy, and it is. What happens when you create some cameras and try to find them?

class Product

Product.find = (query) ->

(product for product in products when product.name is query)

class Camera extends Product

x1 = new Camera 'X1', {}

Product.find 'X1'

# []

The camera was not found! The list of product instances is updated inside the Product constructor. Once you define a new constructor for the Camera class, the Product constructor won’t be invoked when you new a Camera. No Camera instances will be added to the array. There’s a solution to this problem: the super keyword.

5.4.2. super

When Camera extends Product, invoking super inside a method invokes the corresponding inherited method. Suppose that the markup on cameras is massive and they sell at twice the product cost:

class Product

constructor: (name, cost) ->

@name = name

@cost = cost

price: ->

@cost

class Camera extends Product

markup = 2

price: ->

super()*markup

Create a Camera and invoke the price method:

camera = new Camera 'X10', 10

camera.price()

# 20

You can use super with any method call, including a constructor. If you haven’t overridden a method, then the same inherited method that super invokes will be invoked automatically via the prototype. The next listing shows an in-context use of super to call the Product constructor from the Camera constructor. As with other listings in this chapter, you can’t run listing 5.5 from the REPL; you need to run it with listing 5.13.

Listing 5.5. Agtron’s shop client application with camera gallery

In listing 5.5 you notice that passing all of the arguments for a constructor through to the super constructor is repetitive. CoffeeScript also provides super as a keyword for this situation:

class Gallery

class Camera extends Product

constructor: (name, info) ->

@gallery = new Gallery

super

pixelmatic = new Camera 'The Pixelmatic 5000', {}

pixelmatic.name

# 'The Pixelmatic 5000'

Now you know that the CoffeeScript class sugar has been hiding things from you and that syntactic sugar is a language convenience that makes some common expressions easier. When you need to break away from classes, you’ll have to dive back down into objects and prototypes, leaving the sugar behind. So, when do you need to break away from classes?

5.5. Modifying prototypes

Remember, there are plain, old objects and prototype links underneath your classes. In this section you’ll learn how CoffeeScript’s class declarations work by seeing the actual JavaScript they compile to. You’ll also learn what you can do to classes and their instances when you start dynamically modifying their prototypes.

5.5.1. How class declarations work

Imagine now that Agtron has extra stock of some products, and he wants to offer special deals on them. If you know beforehand that Agtron is offering special deals on Cameras with the name 'Lacia', then you can handle the special deal in the class declaration:

It’s not going to be that easy. Agtron wants to change the special deals dynamically. You don’t know in advance what’s going to be discounted, so you can’t declare it in the class. You’ll need to extend the class dynamically. To learn how to extend a class dynamically, you need to learn how classes really work. It’s finally time to see the JavaScript that the CoffeeScript compiler creates from a class declaration.

The compiled JavaScript for a CoffeeScript class is shown in the following listing. As always, CoffeeScript is on the left and compiled JavaScript is on the right.

Listing 5.6. CoffeeScript class and compilation to JavaScript

CoffeeScript

JavaScript

class Simple

constructor: ->

@name = "simple object"

simple = new Simple

var Simple = (function() {

function Simple() {

this.name = 'simple';

}

return Simple;

})();

simple = new Simple();

Inside a CoffeeScript class you see functions. That explains the variable scope. CoffeeScript classes have a variable scope like functions because they are functions. One second, though; where did the constructor go?

Constructor functions

In JavaScript a constructor is a function that creates a new object and links it to a prototype object. In addition to the prototype, all objects have a reference to their constructor function. In JavaScript when you use the new keyword in front of a function, an object is created and the function is invoked with the this keyword inside the function (known as @ in CoffeeScript) referring to the new object. In listings 5.6 and 5.7 the CoffeeScript class constructor corresponds to a constructor function in JavaScript.

Raw constructor functions still work in CoffeeScript:

Any object created using a function as a constructor has a constructor property that references the function. How about methods then? How do they work?

5.5.2. How methods work

The listing that follows shows the compiled JavaScript output for a CoffeeScript class with a constructor and one method.

Listing 5.7. CoffeeScript class, constructor, and method compilation

CoffeeScript

JavaScript

class SteamShovel

constructor (name) ->

@name = name

speak: ->

"Hurry up!"

gus = new SteamShovel

gus.speak()

#Hurry up!

var SteamShovel = (function() {

function SteamShovel(name) {

this.name = name;

}

SteamShovel.prototype.speak =

function() {

return "Hurry up!";

};

return SteamShovel;

};

gus = new SteamShovel();

gus.speak();

The object referenced by SteamShovel.prototype is the prototypical steam shovel. The speak method is created by assigning it as a property on the prototypical steam shovel. You can tell a constructor function which object to use as the prototype for future objects:

SteamShovel.prototype = {}

CoffeeScript classes are syntactic sugar for prototypes and constructor functions. This means you can change properties on the prototype:

SteamShovel.prototype.grumpy = yes

Now all of the objects created using the SteamShovel constructor have a grumpy property, inherited via the prototype chain:

gus.grumpy

# true

This turns out to be useful for dynamically modifying objects and classes.

5.5.3. Dynamic classes

By adding a property to the prototype, you’re adding it to all the objects that use it without touching the class declaration:

class Example

example = new Example

Example.prototype.justAdded = -> "just added!"

example.justAdded()

# "just added!"

You probably remember doing something similar with raw objects in section 4.6 using Object.create. Now you’re doing exactly the same thing by accessing the prototype for a whole class of objects by modifying the prototype object via the class.

Prototype shorthand

CoffeeScript has a more convenient shorthand syntax for accessing the prototype using two consecutive colons, so that

Example::justAdded = -> "just added!"

is equivalent to

Example.prototype.justAdded = -> "just added!"

Understanding what the CoffeeScript compiler does when you write a class means you’re able to modify a class dynamically by modifying the object it uses as the prototype for constructed objects. The next listing demonstrates this in action.

Listing 5.8. Agtron’s shop client application with specials

At this point it’s also informative to show an example of the actual JSON data being used. Here’s an example of this JSON.

Listing 5.9. Product listings with specials

{

'camera': {

'Fuji-X100': {

'description': 'a camera',

'stock': 5,

'arrives': 'December 25, 2012 00:00',

'megapixels': 12.3

}

},

'skateboard': {

'Powell-Peralta': {

'description': 'a skateboard',

'stock': 3,

'arrives': 'December 25, 2012 00:00',

'length': '23.3 inches'

}

}

}

Being JSON, the Shop constructor is able to easily use this data as an object. Remember, JSON is valid syntax for an object in JavaScript and in CoffeeScript. Inside a CoffeeScript program, the data from listing 5.9 can also be represented with significant indentation:

products =

camera:

'Fuji-X100':

description: 'a camera'

stock: 5

arrives: 'December 25, 2012 00:00'

megapixels: 12.3

skateboard:

'Powell-Peralta':

description: 'a skateboard'

stock: 3

arrives: 'December 25, 2012 00:00'

length: '23.3 inches'

Through the prototype of a class you’re able to modify the properties and behavior of many objects at the same time. This can be done not only with your own classes and objects but also with other objects and classes. Remember, the default for all objects is that they’re open to modification. This means you can modify and extend anything, including built-in objects such as the prototypical array.

Objects open by default?

Objects being open means you can change a property on any regular object that you have a reference to. The fifth edition of the ECMAScript standard makes it possible to freeze or seal an object, preventing it from being modified (see chapter 13).

5.6. Extending built-ins

You’ve seen that classes in CoffeeScript are syntactic sugar. They make working with constructors and prototypes easier. There are constructors for objects other than classes you define. Consider an array, an object, and a string:

object = {}

array = []

string = ''

Objects, arrays, and strings each have their own constructor functions. Instead of using the literal notation, it’s possible, if generally pointless, to create objects, arrays, and strings using constructors:

object = new Object

array = new Array

string = new String

The prototypes of these objects provide the methods available to all objects, arrays, and strings. In a sense, there’s a built-in Object class, an Array class, and a String class. But you now know that classes are really a syntactic convenience in CoffeeScript, so it’s more accurate to talk of built-in prototypes and constructor functions.

By modifying built-in prototypes, you can change the behavior of the built-in language. This is a powerful and dangerous technique. In this section you’ll learn how you can use it and why it should be treated with caution.

5.6.1. Built-in constructor prototypes

The built-in constructors provided to you will depend on the runtime you’re using. The constructors you’re most likely to encounter are Object, Array, String, Date, and RegExp.[1] All of these built-in constructors have prototypes that you can modify. For example, consider the joinmethod on an array:

1 A full list of the standard constructors specified by ECMAScript 5 is included in appendix A.

['yin','yang'].join 'and'

# 'yin and yang'

This is a function assigned to the join property of the array prototype, meaning that you have access to it and can change it through Array::join:

Array::join = -> "Array::join was redefined"

['yin','yang'].join 'and'

# "Array::join this was overridden"

You can quite easily break built-in code by assigning silly functions to prototypes. That’s not all there is to them.

5.6.2. Extending date

Agtron now tells you that he wants to display the date when new stock arrives. This will make the homepage look like figure 5.4.

Figure 5.4. Agtron’s shop with stock arrival dates

The stock arrival date is returned in the JSON from the server as a string like this:

"October 13, 1975 11:13:00"

This is a standard date format that the JavaScript runtime can read.[2] You can create a date from it fairly easily using the built-in Date class (otherwise known as the Date constructor function):

2 See IETF RFC 1123 http://tools.ietf.org/html/rfc1123.

new Date "October 13, 1975 11:13:00"

But Agtron wants it to display how many days from today that is. You think that “how many days from today?” is a question you should be able to ask of any date:

productAvailable = new Date "October 13, 1975 11:13:00"

productAvailable.daysFromToday()

Because Date is a constructor, you have access to the prototype for all the date objects. Modify the Date prototype and add a daysFromToday method:

Date::daysFromToday = ->

millisecondsInDay = 86400000

today = new Date

diff = @ - today

Math.floor diff/millisecondsInDay

Travel back in time and imagine that today is January 20, 2012. How many days until Christmas Day 2012?

A warning about dates

Because this executes in a web browser, it will use the time on the user’s computer. Potential issues with date in a browser, such as time zones and clock drift, are beyond the scope of this chapter and not discussed here.

In the next listing you see how to apply this to the client application for Agtron’s shop.

Listing 5.10. Agtron’s shop client application with stock arrivals

Extending prototypes is a powerful technique that allows you to change the behavior of any object in CoffeeScript. You have the power. Be careful how you use it.

5.6.3. Don’t modify objects you don’t own

By extending the built-in Date object, you’re changing it for the entire program. If you’re writing a library that other people are going to use, then you’re changing things for other people’s entire programs. You don’t know what those other people are doing in their programs, so extending built-ins has a high potential for breaking other people’s code. Modifying built-in prototypes is a bit like breaking into somebody’s house and leaving stuff there. This works only if you’re Santa Claus.

One alternative to modifying a built-in prototype is to write your own class that extends the built-in and use that instead:

class ExtendedDate extends Date

daysFromToday: ->

millisecondsInDay = 86400000

today = new Date

diff = @ - today

Math.floor diff/millisecondsInDay

You should trade the convenience of extending a built-in for its danger on a case-by-case basis.

You’ve seen how to declare a class that allows you to create objects from the class. You’ve also seen how classes are just functions and prototypes when you lift the veil and look underneath. Class convenience comes with some rigidity, meaning you go back to raw prototypes when you need to dynamically extend things. This is an important lesson worth repeating.

The class sweet spot

If you’re mostly creating certain kinds of objects with some extensions, then use classes. They work very well for that. If, however, your problem requires more dynamism than structure, you will need to look outside classes.

What if you had lots of objects that were all quite different but nonetheless had some common behavior?

5.7. Mixins

A mixin is a class that contains (mixes together) a combination of methods from other classes. Pure objects and prototypes provide flexibility, and classes provide structure. Mixins are a popular technique in class-based languages to achieve some of the flexibility that prototypes provide while still keeping the structure of classes. Although there’s no dedicated syntax for mixins in CoffeeScript, they can be achieved without much fuss. First though, when should you use mixins? When classes become awkward.

5.7.1. Class inheritance can be awkward

Image now that Agtron wants to add news announcements to the shop homepage. This will make the homepage look like figure 5.5.

Figure 5.5. Agtron’s shop with news announcements

You consider the classes you have in your system, and it looks like you have a small problem. You have a Product class with a render method that’s used by all the objects whose class definition extends Product. Now though, you have a new class, Announcement, that certainly isn’t a Product—it’s awkward if you make it extend Product:

class Announcement

pigsFly = new Announcement

pigsFly.purchase()

# Error

Still, you want to reuse the render method because it really is the same between Product and Announcement. With your inheritance hat on, you think it might be a good idea to just add another layer to the inheritance hierarchy:

class Renderer

class Product extends Renderer

class Camera extends Product

class Announcement extends Renderer

Trying to program like that in CoffeeScript is working against the grain. The objects are dynamic and prototype-based at their core. Work with the language.

Rendering is a function that you just happen to invoke on different objects, some of them products and some of them announcements. The function doesn’t need to belong to a particular class. You can define a render function anywhere in CoffeeScript. The trouble is, when you can define it anywhere, you’re spoiled for choice. If you can define it anywhere, where do you actually define it in practice, and how do you keep related functions together? You want collections of related functions that can be used with objects regardless of what class they were created from—if they were created from a class at all! You want mixins.

5.7.2. Writing a mixin

The simplest way to write a mixin is by taking advantage of the properties as key-value store objects. Define rendering behavior on a plain, old object:

To add the render method to a class, you modify the class prototype:

class Donut

constructor: (name,info) ->

@name = name

@info = info

Now add the render method:

Donut::render = htmlRenderer.render

This works, but it’s tedious. Remember, a mixin is a collection of related functions that can be attached as methods to objects. Suppose you have a collection of three functions:

dwarves =

bashful: -> 'Bashful'

doc: -> 'Doc'

dopey: -> 'Dopey'

To mix dwarves into a FairyTale class, you add all of the functions to the class prototype:

You want a general solution, though, that will work for Camera and looks like so:

How can you make that work? The include function should add all of the properties from the mixin to the class:

That include function is implemented using a comprehension:

Some people prefer to think in terms of classes. A Mixin class, from which you can create instances that provide their own include method, is shown here.

Listing 5.11. Mixin class

By comprehending the properties of an existing object and setting them as properties on another object, you’re able to mix in behavior from one object to another. Note that the mixin technique you’ve learned is static. Once the properties have been copied to the Camera class, further changes to the htmlRenderer object are not seen by Camera instances. Mixins created in this way allow you to do a one-time copy of related functions to another object. More sophisticated dynamic programming is demonstrated in later chapters.

5.7.3. Example: enumerable mixin

Remember the accumulator from chapter 3 that you used to sum an array of numbers? Accumulating numbers wasn’t exciting, but it did demonstrate how to pass a function as an argument to another function:

The accumulate function takes a sequence of numbers and accumulates the values to a single value. Suppose Agtron wants to know the total stock count of all the products on his site. The Product class had a list of instances:

class Product

instances = []

constructor: (stock) ->

instances.push @

@stock = stock

You want to use an accumulator to add up all the stock, but the variable instances is behind the scope of the Product class. You have to accumulate from inside Product:

class Product

instances = []

constructor: (stock) ->

instances.push @

@stock = stock

stock: ->

stockAccumulator = (acc, current) -> acc + current.stock

accumulate(0, instances, stockAccumulator)

The Product class now has a reference to an accumulate variable defined somewhere else that isn’t really a core part of Product. If instead you create an enumerable mixin, then you’ll have a cleaner solution:

Using this enumerable mixin, you can get the stock total:

This somewhat contrived example demonstrates how to keep enumeration out of the Product class. Enumerating isn’t a core concern of a product, so it doesn’t really belong there. Having an enumerable mixin also means that the accumulator can be used in other places in your program.

5.7.4. Mixins from null

You were warned about modifying the prototypes for built-ins. Unfortunately, your colleague Blaine didn’t get the memo, and he has modified the prototype for a built-in inside your program. This is what Blaine did:

Object::antEater = ->

"I'm an ant eater!"

What happens to the enumerable mixin? Not what you want:

antFarm = new Product { stock:1 }

antFarm.antEater()

# "I'm an ant eater!"

All of the Product instances got an antEater method. Remember those warnings about the dangers of extending built-in objects such as Object? People don’t always pay attention to warnings. To avoid getting the new method, you have to guard the comprehension with the own keyword (see chapter 4):

This isn’t bulletproof. To guarantee that you don’t get properties you don’t want, you must explicitly make your mixin an object that’s removed from the prototype chain by making it have null as the prototype. This is done either by passing Object.create the value null as the object to create from

htmlRenderer = Object.create null

or by setting null as the prototype if you use a Mixin class:

class Mixin

@:: = null

constructor: (from, to) ->

for key, val of from

to[key] = val

The null value doesn’t have any properties and it doesn’t have a prototype. If you use it as a prototype, your object won’t inherit any properties from the prototype chain.

5.8. Putting it together

A mixin is not only useful to solve Agtron’s stock counting problem but more generally can be used to clean up some of the aspects of the client program, such as the view, that were embedded in the existing classes without belonging there. In the next listing you see a client program for Agtron’s shop demonstrating the use of mixins to clean up the rendering code. Like other listings in this chapter, this is an example designed to run in a browser.

Listing 5.12. Agtron’s shop client application

Finally, in this listing you see the server-side component of the shop.

Listing 5.13. Agtron’s shop server application

It’s quite common for a web framework to be used to create an application such as the one shown in listings 5.12 and 5.13. The web framework usually provides additional tools to help separate the different parts of your program. But developing the entire application from scratch has helped you to explore some common patterns for using classes and prototypes in CoffeeScript.

5.8.1. Exercise

The server-side part of the shop application doesn’t use any of the techniques described in this chapter. Write a new version that does use them and compare the two.

5.9. Summary

JavaScript and CoffeeScript are languages with prototype-based objects. JavaScript has always had an uncomfortable relationship with classes. Many people have wanted to add classes to JavaScript; the fourth edition of the ECMAScript specification even proposed adding classes to the language, but that edition was abandoned. With the liberty of making significant syntax changes, CoffeeScript can provide a class syntax that will be familiar to developers from most of the popular class-based object-oriented languages in use today. As you saw in this chapter, the underlying prototype-based model is flexible enough to provide classes.

The choice of whether to use classes at all is up to you. Having learned how they work and by extending them, you’ve learned more about prototypes. In some later chapters you’ll compose objects without classes. Before doing that, though, you’ll return to functions and discover techniques borrowed from functional programming in the next chapter.