First-class functions - Foundations - CoffeeScript in Action (2014)

CoffeeScript in Action (2014)

Part 1. Foundations

Chapter 3. First-class functions

This chapter covers

· Functions for representing computation

· Functions for events and event-driven I/O

· An introduction to higher-order functions

· Variable scope and closures

If you asked a dozen JavaScript programmers what they thought JavaScript got wrong, you’d probably get a dozen different answers. If you asked those same dozen people what JavaScript got right, they’d probably all answer, “First-class functions.” What does it mean that JavaScript has first-class functions, why does it matter, and how does CoffeeScript make functions even better? All will be answered in good time. First, though, what exactly is a function?

A function defines a transformation of input values called parameters to an output value called the return value. You define a function in CoffeeScript with literal notation using an arrow:

->

That isn’t a very useful function, though. It has no parameters and no return value. The function parameters go to the left of the arrow, and the function body goes to the right of the arrow:

Parameters Body

(a, b) -> a + b

When you invoke a function, you provide arguments, and the function transforms them to produce an output value:

add = (a, b) -> a + b

add 2, 3

# 5

Notice how this function is assigned to the variable add? That’s an important detail that underpins most of this chapter. You see, functions don’t just produce values; they are values. This means that a function can produce a function as its return value and take a function as an argument. This idea that functions are values is referred to as functions being first-class and leads to the powerful technique of gluing functions together, called function composition.

How does this relate to JavaScript? Functions are just as powerful in JavaScript, but unfortunately functions in JavaScript have some problems. CoffeeScript aims to address these problems and improve the syntax. In this chapter you’ll learn how to use functions for events, callbacks, and higher-order programming and why CoffeeScript syntax is a clearer way to describe functions than the equivalent JavaScript.

3.1. Computation

Imagine your friends Agtron and Scruffy are having a party, and you’ve been tasked with writing a program to count the number of confirmed attendees. When the program counts the attendees for you, it performs a computation. Think of functions as being little computers—they perform computations. To grasp this metaphor, you need to start with some basics.

3.1.1. Basics

You can multiply the numbers 3 and 4 using the multiplication operator:

3 * 4

# 12

Here’s a function to perform the same operation:

When this function is invoked, it evaluates the expressions in the body of the function:

threeTimesFour()

# 12

The last expression evaluated inside the function is the evaluation of the function itself:

That threeTimesFour function isn’t very useful, though. How do you multiply any two numbers? By using function parameters:

Multiplication is rather boring, though, especially when there’s already an operator to do it for you. What are functions good for then? The real power of functions starts when you use them to define new things that don’t have operators. Why? Because when you define things that don’t have operators, you create your own language.

3.1.2. Custom operations

Consider a function to covert gigabytes to megabytes:

gigabytesToMegabytes = (gigabytes) -> gigabytes * 1024

This function defines an operation that isn’t built into the language. Try it:

gigabytesToMegabytes 7

# 7168

What sorts of things do you define in a language? That depends on the problem you’re solving.

Keeping track of attendees

Time to get back to counting the list of party attendees. Imagine a list of confirmed attendees is emailed to you with the name of each confirmed attendee separated from the next by a comma. The list is too long to print here, but the first part of the list looks like this:

'Batman,Joker,Wolverine,Sabertooth,The Green Lantern,Sinestro'

Sounds like a fun party. Anyway, you don’t want to manually count the new list every time it arrives in your inbox. How do you write a program to count the list for you?

CoffeeScript doesn’t have a built-in operator or method to count the number of comma-separated words in a string, but it’s possible to count them by using the split method for strings that you saw in chapter 2. Split the string into an array of strings, and then use the array’s lengthproperty. Try it on the REPL:

If you’re a masochist, then you’ll happily do that over and over again, and over and over again, every time you have another string. Otherwise, you can write a program to count the words and use that program each time you want to count. The following listing contains a CoffeeScript program that runs on Node.js and counts the number of words in a comma-separated string. It reads arguments from the command line using process.argv, which you saw in chapter 2.

Listing 3.1. Counting words

Use this program from the command line by typing coffee followed by the name of the file and then the arguments to the program:

coffee listing.3.1.coffee Batman,Joker,Wolverine,Sabertooth

What does this have to do with functions? Well, functions are a bit like miniprograms. Consider a function that counts comma-separated words in a string:

Enter the one-line countWords function into your REPL and experiment:

countWords 'sight,smell,taste,touch,hearing'

# 5

countWords 'morning,noon,night'

# 3

Functions can do anything—think of the possibilities! Before writing more functions, though, you should review their different parts.

3.1.3. Anatomy

As you’ve seen, a function is written with parameters in parentheses on the left side of an arrow and the function body on the right. But not many functions will fit on one line. If the function body requires multiple lines, then you put the function body underneath, with each line of code indented one level. Refer to figure 3.1.

Figure 3.1. Anatomy of a function

Invocation

When you write the variable name of a function followed by one or more values, then the function is invoked:

countWords 'north,east,south,west'

# 4

Any function is invoked when followed by parameters or parentheses, even a function that’s not assigned to a variable:

(-> 42)()

# 42

The significance of this odd-looking bit of syntax is explored later in the chapter.

Arguments

A function takes any number of values as arguments with a comma separating each argument from the next. These arguments specify values for the function parameters. Why do you need more than one argument? Well, consider a string of words separated by colons:

beerStyles = 'Porter:Pilsner:Stout:Lager:Bock'

The existing countWords function expects words separated by commas, so it doesn’t work for this string. To solve this, add a second parameter to the function that you can use to pass a second argument to the function. This second argument specifies the character to use as the delimiter between each word:

Now the function works for strings delimited by different characters:

countWords('Josie:Melody:Valerie:Alexandra', ':')

# 4

countWords('halloween/scream/maniac', '/')

# 3

countWords('re#brown#tag#table', '#')

# 4

countWords(beerStyles, ':')

# 5

All those parentheses, though; are they necessary? No.

Parentheses

Parentheses around arguments are optional:

But parentheses aren’t optional when you invoke a function without any arguments:

sayHello = -> 'Hello!'

sayHello()

# 'Hello!

Without parentheses or arguments, the function itself is being evaluated, instead of the result of invoking the function:

In general, you should omit parentheses where possible.

Implicit return

The return value for a function is the last expression evaluated when the function is invoked. In JavaScript a function requires an explicit return statement indicating the return value. If there is no such statement, then the return value is undefined:

In CoffeeScript the only way to return undefined from a function is on purpose, by having it as the last expression evaluated:

Return from inside expression

Remember the countWords function?

countWords = (text, delimiter) ->

words = text.split delimiter

words.length

The last expression evaluated is words.length. Suppose that this function doesn’t quite do what you need it to—it has several problems. The first is that it gives an incorrect result for an empty string:

countWords '', ':'

# 1

It does that because that’s how the split method works. Normally for countWords, the way that split works is fine for a single word:

'abc'.split /,/

# ['abc']

But an empty string looks just like a single word:

''.split /,/

# ['']

To fix the empty string problem in countWords, add an if inside it to check whether the text argument is empty or not:

How does this affect the last expression in the function body? It now depends on whether the if or the else branch is evaluated. If the string is empty, then the else branch is evaluated[1] and the last expression is 0. If the string is not empty, then the if branch is evaluated and the last expression is words.length.

1 The else branch is evaluated when text is an empty string because an empty string is a falsy value. Remember, the falsy values are null, false, 0, and ''.

Explicit return statement

You can return early from a function by using the return keyword followed by an expression. An alternative version of countWords with an explicit return statement follows:

The unless keyword you see here isn’t used all that often in CoffeeScript, but it’s very handy and commonly used when returning early from a function. It’s time for a quick detour about how unless works.

Unless

Putting unless after an expression has the opposite effect of putting if after an expression. This means that the following two expressions are equivalent:

eat berries if not poisonous

eat berries unless poisonous

If the expression after the unless keyword is falsy, then the expression before the unless keyword won’t be evaluated.

Back on track now, how does the CoffeeScript function syntax compare to the equivalent JavaScript?

3.1.4. Comparison: JavaScript and CoffeeScript

The next listing presents a side-by-side comparison of JavaScript and CoffeeScript for the latest countWords function. Variable names have been shortened to avoid clutter in the example.

Listing 3.2. Count words comparison

CoffeeScript

JavaScript

countWords = (s, del) ->

if s

words = s.split del

words.length

else

0

var countWords = function (s, del) {

var words;

if (s) {

words = s.split(del);

return words.length;

} else {

return 0;

}

}

CoffeeScript has less syntax than JavaScript for defining functions. Implicit returns aren’t just syntax, though; they also help you think differently about how you write functions. In CoffeeScript, invoked functions have a value by default. This is a change in the semantics of functions that helps you more readily think of functions as expressions.

Where are the named functions?

JavaScript has named functions written by writing the function keyword followed by a name and a function definition:

CoffeeScript, preferring expressions, does not have named functions but only function values assigned to variables.

3.1.5. Exercises

Use these exercises to ensure you understand functions as computations:

· Write a version of countWords that uses space for the word delimiter and ignores words shorter than three letters.

· Write a function that creates a new space-delimited string of words containing only every second word in the original space-delimited string. For example,

· misquote = """we like only like think like when like we like are like confronted like with like a like problem"""

everyOtherWord misquote

should return

'we only think when we are confronted with a problem'

That covers the core ideas behind functions. In order to get to more advanced usage, you now need to look at some real-world problems, warts and all, which will take you on the scenic route to uncovering the power of functions. With your patience in hand, you’ll begin with events.

3.2. Events

Web browsers and Node.js have an event-driven programming model. The core idea of event-driven programming is that program flow reacts to events as they occur instead of prescribing the order in which things must occur. It’s a bit like the difference between sitting in a pizza shop, watching your pizza get cooked, and having it home delivered. The home-delivered pizza is event driven—when the pizza is ready (the ready event), you will receive it, without having to wait around.

In CoffeeScript, functions are used to handle events. A function is registered as an event handler so that when the event occurs, the function is invoked. You’ll see that in this section by looking at creating and handling events with callbacks.

Prerequisite: Running on the client

Some parts of this section require that some CoffeeScript be embedded in an HTML document. Go back to the end of the previous chapter if you need a refresher on how to do that.

3.2.1. Browser events

A quick recap of the program you’ve been writing for Scruffy and Agtron’s party is in order. So far you can count the number of guests attending the party by reading the attendee list from a file called partygoers.txt. Next, you need to create a website for the party that always shows the current attendee count. Scruffy started creating a site for the party, but he had to abandon the project at the last minute to tour Greenland as a xylophonist. Luckily, he had already started on it. You already have an HTML document:

You want to replace the words How many attendees? with the current attendees count. Scruffy also left you some code that shows how to update the content:

So, how do you update the content with the latest attendees? Forget about web browsers entirely for a minute and think about whether you’ve seen anything so far in CoffeeScript to do that. You haven’t, but you’re about to see something that gets you part of the way. It’s calledsetInterval.

document.querySelector?

The document.querySelector method is part of the Document Object Model (DOM) API that you use to manipulate things in a web browser. You’ll find more about browsers in chapter 11.

3.2.2. Using timeouts and intervals to create events

Inside a browser there’s a global setInterval method. It’s a global method because you can invoke it anywhere in your program. The setInterval method is used to make something happen repeatedly, which is exactly what you want for updating the attendees count. First, though, there’s another global method called setTimeout that’s easier for you to experiment with.

The setTimeout method takes two arguments. The first argument is the function to be invoked, and the second argument is the duration (in milliseconds) from the current time that you want the function to be invoked. Try it on the REPL:

The setInterval method works the same way, except that it invokes the function repeatedly. If you enter that into the REPL, then it will continue to be invoked until you exit the REPL or clear the interval.

What does this have to do with functions and events? Continuing the scenic route, it’s all about callbacks.

Global methods

The setTimeout method belongs to a global object. The global object in a web browser is typically the browser’s window object. Other environments have different global objects. Consult the reference for the specific environment.

Callbacks

A callback is a function that’s invoked from somewhere else. You see, normally you invoke a function yourself, whenever you feel the need:

partyMessage()

# It's party time!

A function used as a callback is different. Instead of invoking the function, imagine giving it to Scruffy and asking him to invoke it later. That’s a callback. Similarly, when you invoke setTimeout with partyMessage, you’re telling setTimeout to invoke it later. You’re using thepartyMessage function as a callback.

These callback functions have a very important feature—they’re asynchronous. What does that mean? To find out, try setTimeout partyMessage on the REPL again, but this time make the duration 5 seconds and enter the expression 1+1 before you see the party message appear. Be quick!

setTimeout partyMessage, 5000

1 + 1

# 2

# ... 5 seconds later

# It's party time!

Notice how the REPL evaluated the expression 1+1 before the timeout was complete? That’s why asynchronous callbacks are important; you can go off and do other things while you’re waiting for the response. That’s exactly what Agtron does in figure 3.2 as he waits for Scruffy to call back.

Figure 3.2. Callbacks are asynchronous.

If you created a timeout or interval that you decide you don’t want, you use clearTimeout or clearInterval to clear it:

Back to the task, use setInterval to update the attendee count in the HTML document every second:

Updating with the value 55 every second isn’t exactly what you need, though. Where does the actual attendee count come from? Just as you haven’t seen anything in CoffeeScript to do something repeatedly, you also haven’t seen anything[2] to read input or write output (called I/O). Indeed, there is no way built into the language to do I/O in CoffeeScript (or JavaScript). What do you use instead? You use callback functions.

2 Excluding a brief encounter with fs.readFile in listing 2.4.

3.3. I/O

Continuing the scenic route to the power of functions, you’re presented with a new problem: there’s no easy, built-in way to do I/O in CoffeeScript (or JavaScript). What can you do? The strategy so far for parts of the language you want but that are not built in has been to define a functions for them. It’s the same with I/O; you define a function that specifies how to handle data resulting from I/O.

This method of doing I/O seems tedious at first but has two advantages. First, it means that I/O is asynchronous (something you’ll learn much more about in chapter 9), and second, it means you don’t have to look at the details of how the I/O is implemented. Instead, you concentrate on the callback function. But before you can ignore a detail, you need to appreciate what it is you’re ignoring. The I/O details for fetching data in a web browser are commonly grouped under the term Ajax.

3.3.1. Ajax

Remember that party attendees website? You want the count to update every second, but so far you have no way to actually get the attendee count. Suppose the attendee count is available somewhere on the web; it doesn’t matter where. To get that data into the website you use Ajax to fetch it. Time for a bit of wishful thinking: suppose you already have a get function that does the Ajax for you and that this get function accepts a callback function as an argument:

Figure 3.3 demonstrates how this works across the network.

Figure 3.3. A callback from an external server

The sequence diagram in figure 3.3 is more complicated than the callback you write. Now, the data.js file contains the number of party attendees and you can get the contents of that file with the get method, which does some Ajax for you. All this means that you can use setInterval to regularly trigger a fetch of the latest attendee every second and display that in the HTML page. Here’s the document again:

<!doctype html>

<title>How many people are coming?</title>

<script src='attendees.js'></script>

<body>

<div id='how-many-attendees'>How many attendees?</div>

</body>

</html>

Finally, here’s the client-side script that brings all of this together:

It took a while to get there, but that’s how things work in a web browser. How about on Node.js then? Luckily, it works the same way.

3.3.2. Event-driven file reading with Node.js

Now imagine that you receive a new file called partygoers.txt containing the attendee list every time it changes and that you have access to this file. You already have a way to fetch the attendee count from a web browser, but how do you write a web server that serves up the attendee count by reading it from a file? Reading a file in Node.js looks a lot like the Ajax you just wrote:

Great, now you can read the attendee file. The next step will be to serve the attendee count on the web somewhere so that the website can fetch it using Ajax. Before moving on, though, you might want to spend some time experimenting with file reading to become comfortable with it. Writing a version of a small utility called cat will help you do that.

A cat program

In the following listing is a simple program that’s similar to the cat utility found on Unix-like operating systems. This program prints the contents of a file.

Listing 3.3. Cat utility

Ready to continue and serve a web page using Node.js? Ready for the surprise (or not)? Serving a website involves callback functions.

3.3.3. Event-driven file serving with Node.js

In the next listing, you see a web application that watches a local file for changes and displays the most recent value in a web page. When the file changes, the contents are read in and then assigned to a variable. The value of that variable is then used in the response to HTTP requests.

Listing 3.4. Serve the current contents of a file

This program uses events for reading a file, for watching a file for changes, and for responding to incoming HTTP request events. Every one of these events is handled by a callback function defined in the program.

Although the module system is covered in depth in chapter 12, you’ll see two modules used in this chapter. They are the filesystem module (fs) and the HTTP module (http).

Filesystem module

The Node.js filesystem module fs provides reading from and writing to local files. In listing 3.4 the fs.readFile method, which you’ve already seen, is used in addition to the fs.watchFile method.

The fs.watchFile method takes a file and callback function. The file is polled for changes; when a change is detected, the callback is invoked. The polling is implemented by Node.js interfacing with the operating system.

HTTP module

The Node.js HTTP module provides low-level methods for making HTTP requests and serving HTTP responses. In listing 3.4 a server is created using http.createServer and then told to listen for incoming request events on port 8080 on the host 127.0.0.1.

3.3.4. Exercises

Use these exercises to build your confidence working with programs that contain functions:

· Add a word-counting function to the file-serving code in listing 3.4 so that the web server responds with the number of attendees to the party, given the following attendees list:

'Talos,Gnut,Torg,Ash,Beta,Max,Bender'

· See what happens when you change the list of attendees in the file being watched from the previous exercise.

This ends the scenic route you took to understanding how central functions work in CoffeeScript. In order to achieve anything of practical value (like serving a website), you have to use callback functions. Functions are important, so you must become proficient at using them. This begins with the idea of higher-order functions.

3.4. Higher-order functions

Remember, functions are values. A function can be invoked by another function, supplied as an argument to another function, and be the return value of a function. Using these techniques, functions can be glued together. A function that glues together other functions, composing them, is ahigher-order function.

Suppose you do roughly the same thing every day, a typical example being Monday:

monday = ->

wake()

work()

sleep()

But on Thursday you go to train with your javelin-catching team:

thursday = ->

wake()

work()

catchJavelins()

sleep()

You could have a single function that switched on the day:

activities = (day) ->

switch day

when 'thursday' then catchJavelins()

But now you will be forever updating the activities function. Instead, how about a day function that looks like the following?

day = (freeTime) ->

wake()

work()

freeTime()

sleep()

Now you can define thursday using day and catchJavelins:

thursday = day catchJavelins

Now only thursday has to care about javelin catching. By using the catchJavelins function as a value composing thursday, you’ve made your life a little easier. This composition stuff sounds useful! How else can you compose with functions?

3.4.1. Invoking other functions

Imagine you want to check the attendee list to see if a particular person is attending. How do you write a program for that? You might think to start by using the search method on a string that you learned in chapter 2 (remember, search returns the value -1 if it doesn’t find a match). Consider a contains function that searches a string of comma-separated words:

Unfortunately, this contains function returns the wrong value for the word camp because the word hippocampus contains the word camp:

contains randomWords, 'camp'

#true

In case you missed the memo, false positives are not a design feature. You already have a function that splits these strings into individual words, so back to word counting—here’s a one-liner:

wordCount = (text, delimiter) -> text.split(delimiter).length

Use this as the starting point for a correct contains function.

Reuse

To avoid duplication, you want to reuse this wordCount function, but sadly, it currently does too much for you to be able to reuse it. You need a function that splits the string into an array. So, take out the split and make it a separate function:

split = (text, delimiter) -> text.split delimiter

Now you can define wordCount as a function that invokes split:

wordCount = (text, delimiter) ->

words = split(text, delimiter)

words.length

Now define contains as a function that invokes split and uses the in operator on the array returned by the split function:

contains = (text, delimiter, word) ->

words = split(text, delimiter)

word in words

Because you’re now looking for an actual word occurrence in an array instead of a match across the entire string, this new version of contains works correctly with the word camp:

contains randomWords, ',', 'camp'

# false

Invoking the split function from inside the contains function demonstrates another function composition—invoking one function from another.

3.4.2. Example: Counting words in a file

Counting words in comma-separated strings can be extended to a more general word-counting program similar to the wc utility on Unix-like operating systems. Here’s a Node.js program for counting the number of words in a file. It demonstrates the techniques used so far, as well as revisiting array comprehensions.

Listing 3.5. Counting words

Where’s reduce?

If you’re thinking that the countMany function could have just reduced the array instead of iterating manually, you’re correct. If you don’t know what reduce is, then that’s fine too; carry on.

3.4.3. Functions as arguments

Good news! You’ve already seen functions used as arguments. For example, the setTimeout method takes a function as an argument:

invokeLater = -> console.log 'Please invoke in one second'

setTimeout invokeLater, 1000

This has uses other than callback functions, though.

Summing an array

Just when you thought you had the party attendee count page covered, there’s a problem. People are allowed to bring friends to the party, and those friends aren’t being included in the attendee list. Instead, you’re now getting emailed another guests file containing the number of friends each person is bringing. Like the attendee list, the guest list is too long to print here, but it’s in this format:

'1,2,0,2,8,0,1,3'

You already have a split function to split comma-separated strings, but you’ll need a way to add up the numbers returned. To do this you’ll need a sum function that works as follows:

numbers = [1,2,0,2,8,0,1,3]

sum numbers

# 17

You haven’t written the function yet, but that’s how it should work.

Writing accumulate

One way to add the numbers in an array is by keeping a total and adding each one in turn:

Suppose you want to multiply the numbers instead of sum them. Do you write another function?

The multiply function looks almost exactly like the sum function! Now suppose you want to flatten an array of arrays so that [[1,2],[2,2],[4,2]] will become [1,2,2,2,4,2]. How do you do that? You could write yet another function that looks just like the last two:

Now you have three similar functions. That’s two too many. Instead of having different variants of the same function, if only you could avoid this repetition and have the common parts of the three functions in one place and the differences in another. Indeed you can! Extract the common parts of add, multiply, and flatten into a single function that takes another function as an argument. The function passed in as the argument will perform the parts that are different. Now, instead of using specific add, multiply, and flatten functions, you’ve abstracted away the common parts and made an accumulate function:

Inside accumulate, instead of there being a primitive operator such as + or *, you see the name of the argument, accumulator. Use the new accumulate function to sum an array:

Now use the accumulate function to flatten an array:

flatten = (acc,current) -> acc.concat current

accumulate([], [[1,3],[2,8]], flatten)

# [1,3,2,8]

Try to visualize this accumulate function to understand how it works.

Visualizing accumulate

Suppose you want to manually add the numbers from 1 through 5. Insert an addition operator between the numbers, as in figure 3.4.

Figure 3.4. Summing numbers with operator

When you use the accumulate function, you’re doing the same thing, except that instead of an operator you insert a function between the numbers, as in figure 3.5.

Figure 3.5. Summing numbers by folding in a function

You might visualize it as folding the function into the array. In some programming languages it’s actually called fold, and when the function is inserted to the left (as in figure 3.5), it’s called fold left or foldl.

Recursion!

If you think that the flatten function shown won’t completely flatten deeply nested arrays such as [1,[3,[4,5]]], then you’re correct. Using recursion will be explored in chapter 6.

Before you had three similar functions to add, multiply, and flatten an array. Now you have one accumulate function that’s an abstraction of the general idea of accumulating, or folding a function into an array or other data structure. The next important concept to learn for functions isscope. First, though, a quick mention of some syntax called default arguments that will tidy up some of what you’ve seen in this section.

Strategy pattern

If you have a background in design patterns from object-oriented programming languages, you might recognize that the way a function is passed in here is essentially a lightweight strategy pattern. If you don’t know design patterns, you’ve just learned your first one!

Default argument values

The accumulate function uses a default value of 0 for the total. Instead of having to do this in the body of the function, you can use a default argument value. So, instead of

accumulate = (initial, numbers, accumulator) ->

total = initial or 0

# <rest of function omitted>

you can use

accumulate = (initial=0, numbers, accumulator) ->

total = initial

# <rest of function omitted>

Try a basic version of this on the REPL:

logArgument = (logMe='default') -> console.log logMe

logArgument()

# 'default'

logArgument('not the default')

# 'not the default'

3.4.4. Exercises

It’s time for some exercises to help you explore the concepts you’ve just learned:

· Use accumulate to create a sumFractions function that will sum fractions supplied as strings and return a fraction as a string. For example,

sumFractions ['2/6', '1/4']

should return '7/12' or an equivalent fraction such as '14/24'.

· Write a keep function that takes an array and returns a new array containing only the element of the array that meets a condition supplied by a function. For example,

· greaterThan3 = (n) -> n > 3

keep [1,2,3,4], greaterThan3

should return an array containing the single value 4.

The next important composition technique involves using functions as return values and a concept called closures. In order to get there, you must first understand how the scope rules work inside functions.

3.5. Scope

Remember earlier when you defined a function called accumulate? Suppose this function is in a program you wrote and that one day your colleague Robin works on the program and adds this doozy to it:

accumulate = yes

Your program is broken and many of your tests fail. Just as individual programs have their own variables, you need a way to isolate individual components of your program so that a variable name in one part of the program doesn’t accidentally overwrite or clobber the same variable name in another part of the program. You need scope.

3.5.1. Lexical function scope

All variables are lexically scoped to the body of a function and are defined only inside that function. In this section you’ll see that implicit variable definitions in CoffeeScript can help prevent name collisions and global variables that can be a common affliction in JavaScript programs.

Functions are like programs with their own variables. If you first define a variable inside a function, then it can’t be used outside the function:

A variable that’s scoped to a function is undefined outside of the function. This means you can have one part of the program where you use the name accumulate for one variable and another part of the program where Robin uses the name accumulate for a different variable:

subProgramOne = ->

accumulate = (initial, numbers, accumulator) ->

total = initial or 0

for number in numbers

total = accumulator total, number

total

subProgramTwo = ->

accumulate = yes

The two uses of accumulate in this example are different variables; functions provide scope.

3.5.2. No block scope

Function scope is the only lexical scope rule in CoffeeScript; there is no block scope. If subProgramOne and subProgramTwo are there only to provide scope, then there is no reason to assign them to variables. You can invoke a function literal directly:

(->

name = 'Ren'

)()

(->

name = 'Stimpy'

)()

This syntax is a bit clunky, so CoffeeScript provides an alternative way to invoke a function using the do keyword:

do ->

name = 'Ren'

do ->

name = 'Stimpy'

Putting the do keyword in front of a function has the same result as putting parentheses after one—invoking it.

3.5.3. Implicit variable declarations

As described, lexical function scope in CoffeeScript works exactly the same as it does in JavaScript. There’s one crucial difference between CoffeeScript and JavaScript, though: in CoffeeScript all variable declarations are implicit. Variable declarations in JavaScript are explicit because to create a variable you need to use the var keyword:

What happens in JavaScript when you assign a value to a variable that has not been explicitly scoped to the function with var? The variable is declared globally for you.[3] See chapter 13. This is a massive problem in a browser environment where scripts from many sources that have potentially never been tested together are loaded into a single webpage sharing a single global scope.

3 The fifth edition of the ECMAScript specification can help with this problem in JavaScript.

It was one thing for Robin to accidentally clobber your variable; it’s another thing for a website running your script to load another script that accidentally or even deliberately clobbers your variables. The previous example would be written in CoffeeScript as

scope = ->

x = 1

y = 2

The variables will be defined in the current function scope implicitly. It’s not possible to create a global variable unless you’re explicitly trying to.

CoffeeScript variables don’t require a var keyword; when an assignment to a variable is made, the name is first looked for in the current scope. If it isn’t found, then it’s created in the current scope. Because it isn’t possible to create a new local variable that already exists in an outer scope, CoffeeScript is said to not have variable shadowing:

Implicit variable definition in CoffeeScript means that variables can’t accidentally be defined on the global scope. CoffeeScript goes one step further, though; in order to stop variables being placed in the global scope at all, the CoffeeScript compiler wraps the code in each compiled file in a scope, essentially doing this:

do ->

# <your program here>

Except your CoffeeScript program is compiled to JavaScript, so it’s actually wrapped in this:

(function() {

// <your compiled program goes here>

}).call(this);

This does the same thing—creates a scope—but it uses the call method on the function and passes this as the argument. Both call and this are still relevant to CoffeeScript; if you don’t already know them from JavaScript, this is covered in chapter 4 and call is covered in chapter 6.

3.5.4. Nesting

Functions are first-class values. Not only can you call a function from another function and pass a function to another function, but you can also define a function inside another function where lexical function scope rules still apply. This means that a function defined inside a function has access to all the variables in the outer function.

Consider the existing array flatten function and how you invoke your accumulate function with it:

flatten = (acc,current) -> acc.concat current

accumulate([], [[1,3],[2,8]], flatten)

Any time you need to flatten an array, you’ll need to remember two functions; that’s one more than you need. Instead, define a single function that combines them:

To explore this, consider the following example that uses the existential operator to demonstrate which variables are defined where:

The same rules apply no matter how far down you go. A lexical function scopes all the way down.

Argument scope

Function arguments follow the same lexical scoping rules as function variables, with the exception that arguments with the same name will shadow. Compare this example

with the following:

Although you have access to the arguments passed to a containing function, if you use the same argument name for a function scoped inside that containing function, then the inner function won’t have access to the outer function argument. The name of an argument will shadow the name of a variable or argument in an outer scope.

Functions as return values

Perhaps you’re thinking at this point that as awesome as this all sounds, nested scopes don’t seem to buy you much. Why would you want to nest functions like this? You’re about to find out.

You see, there’s one more thing you can do with functions as values: you can return a function from a function. Pause for a minute and think what might happen to the scoped variables when a function is returned from a function:

This is your introduction to closures.

3.6. Closures

To newcomers, the idea of closures is often shrouded in mystery, so it’s useful to first look at where they come from. Peter Landin coined the term closure, with the meaning used in CoffeeScript, in 1964 when he was implementing a virtual machine called the SECD[4] machine. Strictly speaking, it means that functions close over the free variables in their lexical scope. This has some profound importance that you need to see in action to appreciate. In this section you’ll learn how closures work and how they not only help you get away from problematic global state but also provide a new composition technique when functions are used as return values.

4 SECD stands for Stack Environment Code Dump.

3.6.1. Global state problems

In listing 3.4 you saw the contents of a file stored in a variable after it was read, so that it could be used by another function. Suppose you have two files, tweedle.dum and tweedle.dee, and you always want to serve the contents of the one that was most recently modified. Suppose you want to implement this as a function that will serve the most recently modified file:

serveMostRecentFile 'tweedle.dum', 'tweedle.dee'

This will involve another piece of function glue—functions as return values.

3.6.2. Functions as return values

Suppose now you don’t want to just serve the most recent file. Instead, you want to use the most recent file’s contents somewhere else in your program. As it’s written now, though, because you’ve contained the variables inside a scope, you’re unable to access them in other parts of your program. You need a way to expose a specific variable from a scope to other parts of your program, without resorting to a global variable. To do this, you write another function. This function is going to use a new piece of programming glue that you’ve not seen yet, by using a function as the return value from a function. In order to get there and understand what’s happening, it’s worth first looking at a simple example of the concept to see how it works.

Abstract example

A simple, abstract example that illustrates the concept of returning a function from a function is a good place to start:

When you invoke makeIncrementer, you get back a function that increments the value of the variable n and returns the value:

incrementer = makeIncrementer()

incrementer()

# 1

incrementer()

# 2

Is it an object?

If closures are new to you but you’re comfortable with objects, then you might think of a closure as an object. Suppose you had an incrementer object with a single method called increment that incremented an internal value and returned it. This would be essentially the same thing as the closure demonstrated in this section.

The returned function has access to the variables scoped to makeIncrementer. The returned function closes over the variables in scope, resulting in closure. Each time makeIncrementer is invoked, a new closure is created, meaning you can have several of them:

up = makeIncrementer()

oneMore = makeIncrementer()

up()

# 1

up()

# 2

up()

# 3

oneMore()

# 1

Applied example

This same technique can be used to create a function that will always return the contents of the most recently modified of two files:

makeMostRecent = (file1, file2) ->

mostRecent = 'Nothing read yet.'

sourceFileWatcher = (fileName) ->

sourceFileReader = ->

fs.readFile fileName, 'utf-8', (error, data) ->

mostRecent = data

fs.watch fileName, sourceFileReader

sourceFileWatcher file1

sourceFileWatcher file2

getMostRecent = ->

mostRecent

This function can be used like so:

mostRecentTweedle = makeMostRecent 'tweedle.dee', 'tweedle.dum'

If tweedle.dee has been changed most recently and it contained

Contrariwise

then invoking the returned function will produce that text:

The mostRecent variable is a free variable inside the getMostRecent function because it’s not defined inside its function but inside the outer makeMostRecent function. Directly inside makeMostRecent, the mostRecent variable is a bound variable.

Closure says that free variables are closed over by a function that has them available via lexical scope, meaning that the function assigned to getMostRecent always has access to the mostRecent variable regardless of when or where it’s invoked. As a result, even though themakeMostRecent function has already been invoked, the function returned from it still has access to its bound variables, via closure.

Closure and arguments

Function arguments are also closed over:

closedOverArgument = (x) ->

-> x

five = closedOverArgument 5

nine = closedOverArgument 9

five()

# 5

nine()

# 9

In that sense, the arguments to a function act like locally defined variables. The scoping rules for arguments are the same as for variables with the exception that argument names shadow names in outer functions, whereas variable names don’t.

3.6.3. Extended example: using closure

The new watchedFileReader function allows you to now solve the problem without having to have a global variable to share state around the program. Here’s a modification of the program from listing 3.4 that uses closures and serves the combined contents of multiple files.

Listing 3.6. Serve multiple files

Using closure, you’ve been able to isolate two parts of your program and provide a way to get data from one part of a program to another.

3.7. Putting it together

You’ve looked at functions as discrete parts of a program that use values as arguments, contain expressions, and return values. You’ve also looked at functions themselves as values and at some of the powerful abstraction techniques that provides. All of this was done in the context of creating a website for Agtron and Scruffy’s party. Finally, you have all of the building blocks to create the full solution.

The following listing provides the program to serve a web page with the total number of guests at Scruffy and Agtron’s party using the techniques and concepts from this chapter. Note that this listing requires the compiler to be available as a module, so to run it you first need to run npm install coffee-script from the command line in the folder you want to run it from. Exactly what modules are and what npm install does are covered in chapter 12. For now, on to the listing.

Listing 3.7. The party website

This entire program is more complicated than anything you’ve seen before in CoffeeScript. But everything in it is either a general syntactic feature of CoffeeScript or a technique for using functions that you’ve learned in this chapter. It’s apparent, though, that if this program were to get larger, then new tools and techniques for composing functions and programs and new ways of thinking about how to design them would be needed. For now, though, you have enough to start writing applications, from functions all the way down.

3.8. Summary

Functions are first-class values in CoffeeScript. They’re used for structuring programs at several levels and allow you to group together multiple expressions, treating them like a single expression. By assigning function values to a variable, you have names for functions that you use to organize programs.

First-class functions used as callbacks are a fundamental I/O technique used both in the browser and on the client. You’ve seen repeatedly how this technique works in different contexts and how it allows I/O to be treated with the same techniques whether it’s local file access or across a network. This idea has some important implications and advantages that will be explored later on.

Functions are combined by invoking them inside other functions, by passing them as arguments to other functions, and by using functions as return values from other functions. By gluing functions together, you can use them to create abstractions of other functions, as you saw in theaccumulator function.

Closure provides a way to isolate parts of a program by containing the variables defined within them, and by passing closures around in your programs you can use them to carry data. In one sense, closures provide some of the features that you’ll see objects provide in the next chapter but with a different conceptual model and a different sweet spot for where they’re used.

Finally, CoffeeScript blends ideas from different programming languages. Although it supports some important functional programming techniques, it also supports techniques from object-based languages. You’ll see those techniques in the next chapter.