# Think Javascript

The Adelphi University Mod of Think Python ports to Javascript the Learning with Python 3 (RLE) edition by Peter Wentworth.

Copyright (C) 2018. Matthew X. Curinga.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with Invariant Sections being Foreword, Preface, and Contributor List, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”.

# Forward

## A very brief forward to the Javascript edition

In the Ed Tech department at Adelphi, we have switched our introductory programming courses from Python to Javascript. Javascript has many of the features we like about Python, but also offers easy congiguration and a path to developing web and mobile apps without introducing additional programming languages. Most of the text is a straight port of the Python text, with some details to the specific Javascript features. The chapters are augmented with video tutorials and large code samples that focus on unstructured problem solving.

## Foreword to Learning with Python 3 (RLE)

By David Beazley

As an educator, researcher, and book author, I am delighted to see the completion of this book. Python is a fun and extremely easy-to-use programming language that has steadily gained in popularity over the last few years. Developed over ten years ago by Guido van Rossum, Python’s simple syntax and overall feel is largely derived from ABC, a teaching language that was developed in the 1980’s. However, Python was also created to solve real problems and it borrows a wide variety of features from programming languages such as C++, Java, Modula-3, and Scheme. Because of this, one of Python’s most remarkable features is its broad appeal to professional software developers, scientists, researchers, artists, and educators.

Despite Python’s appeal to many different communities, you may still wonder why Python? or why teach programming with Python? Answering these questions is no simple task—especially when popular opinion is on the side of more masochistic alternatives such as C++ and Java. However, I think the most direct answer is that programming in Python is simply a lot of fun and more productive.

When I teach computer science courses, I want to cover important concepts in addition to making the material interesting and engaging to students. Unfortunately, there is a tendency for introductory programming courses to focus far too much attention on mathematical abstraction and for students to become frustrated with annoying problems related to low-level details of syntax, compilation, and the enforcement of seemingly arcane rules. Although such abstraction and formalism is important to professional software engineers and students who plan to continue their study of computer science, taking such an approach in an introductory course mostly succeeds in making computer science boring. When I teach a course, I don’t want to have a room of uninspired students. I would much rather see them trying to solve interesting problems by exploring different ideas, taking unconventional approaches, breaking the rules, and learning from their mistakes. In doing so, I don’t want to waste half of the semester trying to sort out obscure syntax problems, unintelligible compiler error messages, or the several hundred ways that a program might generate a general protection fault.

One of the reasons why I like Python is that it provides a really nice balance between the practical and the conceptual. Since Python is interpreted, beginners can pick up the language and start doing neat things almost immediately without getting lost in the problems of compilation and linking. Furthermore, Python comes with a large library of modules that can be used to do all sorts of tasks ranging from web-programming to graphics. Having such a practical focus is a great way to engage students and it allows them to complete significant projects. However, Python can also serve as an excellent foundation for introducing important computer science concepts. Since Python fully supports procedures and classes, students can be gradually introduced to topics such as procedural abstraction, data structures, and object-oriented programming — all of which are applicable to later courses on Java or C++. Python even borrows a number of features from functional programming languages and can be used to introduce concepts that would be covered in more detail in courses on Scheme and Lisp.

In reading Jeffrey’s preface, I am struck by his comments that Python allowed him to see a higher level of success and a lower level of frustration and that he was able to move faster with better results. Although these comments refer to his introductory course, I sometimes use Python for these exact same reasons in advanced graduate level computer science courses at the University of Chicago. In these courses, I am constantly faced with the daunting task of covering a lot of difficult course material in a blistering nine week quarter. Although it is certainly possible for me to inflict a lot of pain and suffering by using a language like C++, I have often found this approach to be counterproductive—especially when the course is about a topic unrelated to just programming. I find that using Python allows me to better focus on the actual topic at hand while allowing students to complete substantial class projects.

Although Python is still a young and evolving language, I believe that it has a bright future in education. This book is an important step in that direction. David Beazley University of Chicago Author of the Python Essential Reference

## Contributor List

To paraphrase the philosophy of the Free Software Foundation, this book is free like free speech, but not necessarily free like free pizza. It came about because of a collaboration that would not have been possible without the GNU Free Documentation License. So we would like to thank the Free Software Foundation for developing this license and, of course, making it available to us.

We would also like to thank the more than 100 sharp-eyed and thoughtful readers who have sent us suggestions and corrections over the past few years. In the spirit of free software, we decided to express our gratitude in the form of a contributor list. Unfortunately, this list is not complete, but we are doing our best to keep it up to date. It was also getting too large to include everyone who sends in a typo or two. You have our gratitude, and you have the personal satisfaction of making a book you found useful better for you and everyone else who uses it. New additions to the list for the 2nd edition will be those who have made on-going contributions.

If you have a chance to look through the list, you should realize that each person here has spared you and all subsequent readers from the confusion of a technical error or a less-than-transparent explanation, just by sending us a note.

Impossible as it may seem after so many corrections, there may still be errors in this book. If you should stumble across one, we hope you will take a minute to contact us. The email address (for the Python 3 version of the book) is . Substantial changes made due to your suggestions will add you to the next version of the contributor list (unless you ask to be omitted). Thank you!

### Second Edition

• An email from Mike MacHenry set me straight on tail recursion. He not only pointed out an error in the presentation, but suggested how to correct it.
• It wasn’t until 5th Grade student Owen Davies came to me in a Saturday morning Python enrichment class and said he wanted to write the card game, Gin Rummy, in Python that I finally knew what I wanted to use as the case study for the object oriented programming chapters.
• A special thanks to pioneering students in Jeff’s Python Programming class at GCTAA during the 2009-2010 school year: Safath Ahmed, Howard Batiste, Louis Elkner-Alfaro, and Rachel Hancock. Your continual and thoughtfull feedback led to changes in most of the chapters of the book. You set the standard for the active and engaged learners that will help make the new Governor’s Academy what it is to become. Thanks to you this is truly a student tested text.
• Thanks in a similar vein to the students in Jeff’s Computer Science class at the HB-Woodlawn program during the 2007-2008 school year: James Crowley, Joshua Eddy, Eric Larson, Brian McGrail, and Iliana Vazuka.
• Ammar Nabulsi sent in numerous corrections from Chapters 1 and 2.
• Aldric Giacomoni pointed out an error in our definition of the Fibonacci sequence in Chapter 5.
• Roger Sperberg sent in several spelling corrections and pointed out a twisted piece of logic in Chapter 3.
• Adele Goldberg sat down with Jeff at PyCon 2007 and gave him a list of suggestions and corrections from throughout the book.
• Ben Bruno sent in corrections for chapters 4, 5, 6, and 7.
• Carl LaCombe pointed out that we incorrectly used the term commutative in chapter 6 where symmetric was the correct term.
• Alessandro Montanile sent in corrections for errors in the code examples and text in chapters 3, 12, 15, 17, 18, 19, and 20.
• Emanuele Rusconi found errors in chapters 4, 8, and 15.
• Michael Vogt reported an indentation error in an example in chapter 6, and sent in a suggestion for improving the clarity of the shell vs. script section in chapter 1.

### First Edition

• Lloyd Hugh Allen sent in a correction to Section 8.4.
• Yvon Boulianne sent in a correction of a semantic error in Chapter 5.
• Fred Bremmer submitted a correction in Section 2.1.
• Jonah Cohen wrote the Perl scripts to convert the LaTeX source for this book into beautiful HTML.
• Michael Conlon sent in a grammar correction in Chapter 2 and an improvement in style in Chapter 1, and he initiated discussion on the technical aspects of interpreters.
• Benoit Girard sent in a correction to a humorous mistake in Section 5.6.
• Courtney Gleason and Katherine Smith wrote horsebet.py, which was used as a case study in an earlier version of the book. Their program can now be found on the website.
• Lee Harr submitted more corrections than we have room to list here, and indeed he should be listed as one of the principal editors of the text.
• James Kaylin is a student using the text. He has submitted numerous corrections.
• David Kershaw fixed the broken catTwice function in Section 3.10.
• Eddie Lam has sent in numerous corrections to Chapters 1, 2, and 3. He also fixed the Makefile so that it creates an index the first time it is run and helped us set up a versioning scheme.
• Man-Yong Lee sent in a correction to the example code in Section 2.4.
• David Mayo pointed out that the word unconsciously in Chapter 1 needed to be changed to subconsciously .
• Chris McAloon sent in several corrections to Sections 3.9 and 3.10.
• Matthew J. Moelter has been a long-time contributor who sent in numerous corrections and suggestions to the book.
• Simon Dicon Montford reported a missing function definition and several typos in Chapter 3. He also found errors in the increment function in Chapter 13.
• John Ouzts corrected the definition of return value in Chapter 3.
• Kevin Parks sent in valuable comments and suggestions as to how to improve the distribution of the book.
• David Pool sent in a typo in the glossary of Chapter 1, as well as kind words of encouragement.
• Michael Schmitt sent in a correction to the chapter on files and exceptions.
• Robin Shaw pointed out an error in Section 13.1, where the printTime function was used in an example without being defined.
• Paul Sleigh found an error in Chapter 7 and a bug in Jonah Cohen’s Perl script that generates HTML from LaTeX.
• Craig T. Snydal is testing the text in a course at Drew University. He has contributed several valuable suggestions and corrections.
• Ian Thomas and his students are using the text in a programming course. They are the first ones to test the chapters in the latter half of the book, and they have make numerous corrections and suggestions.
• Keith Verheyden sent in a correction in Chapter 3.
• Peter Winstanley let us know about a longstanding error in our Latin in Chapter 3.
• Chris Wrobel made corrections to the code in the chapter on file I/O and exceptions.
• Moshe Zadka has made invaluable contributions to this project. In addition to writing the first draft of the chapter on Dictionaries, he provided continual guidance in the early stages of the book.
• Christoph Zwerschke sent several corrections and pedagogic suggestions, and explained the difference between gleich and selbe.
• James Mayer sent us a whole slew of spelling and typographical errors, including two in the contributor list.
• Hayden McAfee caught a potentially confusing inconsistency between two examples.
• Angel Arnal is part of an international team of translators working on the Spanish version of the text. He has also found several errors in the English version.
• Tauhidul Hoque and Lex Berezhny created the illustrations in Chapter 1 and improved many of the other illustrations.
• Dr. Michele Alzetta caught an error in Chapter 8 and sent some interesting pedagogic comments and suggestions about Fibonacci and Old Maid.
• Andy Mitchell caught a typo in Chapter 1 and a broken example in Chapter 2.
• Kalin Harvey suggested a clarification in Chapter 7 and caught some typos.
• Christopher P. Smith caught several typos and is helping us prepare to update the book for Python 2.2.
• David Hutchins caught a typo in the Foreword.
• Gregor Lingl is teaching Python at a high school in Vienna, Austria. He is working on a German translation of the book, and he caught a couple of bad errors in Chapter 5.
• Julie Peters caught a typo in the Preface.

# The way of the program

The goal of this book is to teach you to think like a computer scientist. This way of thinking combines some of the best features of mathematics, engineering, and natural science. Like mathematicians, computer scientists use formal languages to denote ideas (specifically computations). Like engineers, they design things, assembling components into systems and evaluating tradeoffs among alternatives. Like scientists, they observe the behavior of complex systems, form hypotheses, and test predictions.

The single most important skill for a computer scientist is problem solving. Problem solving means the ability to formulate problems, think creatively about solutions, and express a solution clearly and accurately. As it turns out, the process of learning to program is an excellent opportunity to practice problem-solving skills. That’s why this chapter is called, The way of the program.

On one level, you will be learning to program, a useful skill by itself. On another level, you will use programming as a means to an end. As we go along, that end will become clearer.

## The Javascript programming language

The programming language you will be learning is Javascript. Javascript is an example of a high-level language; other high-level languages you might have heard of are Python, C++, PHP, Pascal, C#, and Java. It’s important to point out that Java and Javascript are two different programming languages with different syntax, styles, purposes, and histories. They unfortunately, share a very close name!

As you might infer from the name high-level language, there are also low-level languages, sometimes referred to as machine languages or assembly languages. Loosely speaking, computers can only execute programs written in low-level languages. Thus, programs written in a high-level language have to be translated into something more suitable before they can run.

Almost all programs are written in high-level languages because of their advantages. It is much easier to program in a high-level language so programs take less time to write, they are shorter and easier to read, and they are more likely to be correct. Second, high-level languages are portable, meaning that they can run on different kinds of computers with few or no modifications.

The engine that translates and runs Javascript is called the Javascript Interpreter. All modern web browser (Firefox, Chrome, Safari, MS Edge/IE, etc) ship with a Javascript interpreter. You can also install a stand-alone interpreter on your computer.

The longer code examples in this book will use Repl.it, an online programming platform and community. Code listings include links to the “repl” that you can copy (“fork”) and experiment with.

There are two ways to use the interpreter: interactive or immediate mode and script mode. In immediate mode, you type Javascript expressions into the interpreter’s console, and the interpreter immediately shows the result. This is the an example of the repl.it interpreter’s console:

Babel Compiler v6.4.4
Copyright (c) 2014-2015 Sebastian McKenzie

⠕ 2+2
=> 4

The 2+2 is entered at the Javascript prompt. The ⠕ token indicates a statement entered at the prompt. The interpreter uses the prompt to indicate that it is ready for instructions. We typed 2 + 2 and hit enter the interpreter evaluated our expression, and replied 4, and on the next line it gave a new prompt. In this case, 4 is the output and it is indicated as output in our console by the => token.

Alternatively, you can write a program in a file and use the interpreter to execute the contents of the file. Such a file is called a script. Scripts have the advantage that they can be saved to disk, printed, shared, and so on.

For example, we created a file named main.js using our text editor. By convention, files that contain Javascript programs have names that end with .js, but they are just plain-text files.

To execute the program in repl.it, we simply click the “run” button. The output is shown in the console.

Working directly in the interpreter is convenient for testing short bits of code because you get immediate feedback. Think of it as scratch paper used to help you work out problems. Anything longer than a few lines should be put into a script.

## What is a program?

A program is a sequence of instructions that specifies how to perform a computation. The computation might be something mathematical, such as solving a system of equations or finding the roots of a polynomial, but it can also be a symbolic computation, such as searching and replacing text in a document or (strangely enough) compiling a program.

The details look different in different languages, but a few basic instructions appear in just about every language:

input

Get data from the keyboard, a file, or some other device.

output

Display data on the screen or send data to a file or other device.

math

Perform basic mathematical operations like addition and multiplication.

conditional execution

Check for certain conditions and execute the appropriate sequence of statements.

repetition

Perform some action repeatedly, usually with some variation.

Believe it or not, that’s pretty much all there is to it. Every program you’ve ever used, no matter how complicated, is made up of instructions that look more or less like these. Thus, we can describe programming as the process of breaking a large, complex task into smaller and smaller subtasks until the subtasks are simple enough to be performed with sequences of these basic instructions.

That may be a little vague, but we will come back to this topic later when we talk about algorithms.

## What is debugging?

Programming is a complex process, and because it is done by human beings, it often leads to errors. Programming errors are called bugs and the process of tracking them down and correcting them is called debugging. Use of the term bug to describe small engineering difficulties dates back to at least 1889, when Thomas Edison had a bug with his phonograph.

Three kinds of errors can occur in a program: syntax errors, runtime errors, and semantic errors. It is useful to distinguish between them in order to track them down more quickly.

## Syntax errors

Javascript can only execute a program if the program is syntactically correct; otherwise, the process fails and returns an error message. Syntax refers to the structure of a program and the rules about that structure. For example, in English, a sentence must begin with a capital letter and end with a period. this sentence contains a syntax error. So does this one

For most readers, a few syntax errors are not a significant problem, which is why we can read the poetry of E. E. Cummings without (too many) problems. Javascript is not so forgiving. If there is a single syntax error anywhere in your program, Javascript will display an error message and quit, and you will not be able to run your program. During the first few weeks of your programming career, you will probably spend a lot of time tracking down syntax errors. As you gain experience, though, you will make fewer errors and find them faster.

## Runtime errors

The second type of error is a runtime error, so called because the error does not appear until you run the program. These errors are also called exceptions because they usually indicate that something exceptional (and bad) has happened.

Runtime errors are rare in the simple programs you will see in the first few chapters, so it might be a while before you encounter one.

## Semantic errors

The third type of error is the semantic error. If there is a semantic error in your program, it will run successfully, in the sense that the computer will not generate any error messages, but it will not do the right thing. It will do something else. Specifically, it will do what you told it to do.

The problem is that the program you wrote is not the program you wanted to write. The meaning of the program (its semantics) is wrong. Identifying semantic errors can be tricky because it requires you to work backward by looking at the output of the program and trying to figure out what it is doing.

## Experimental debugging

One of the most important skills you will acquire is debugging. Although it can be frustrating, debugging is one of the most intellectually rich, challenging, and interesting parts of programming.

In some ways, debugging is like detective work. You are confronted with clues, and you have to infer the processes and events that led to the results you see.

Debugging is also like an experimental science. Once you have an idea what is going wrong, you modify your program and try again. If your hypothesis was correct, then you can predict the result of the modification, and you take a step closer to a working program. If your hypothesis was wrong, you have to come up with a new one. As Sherlock Holmes pointed out, When you have eliminated the impossible, whatever remains, however improbable, must be the truth. (A. Conan Doyle, The Sign of Four)

For some people, programming and debugging are the same thing. That is, programming is the process of gradually debugging a program until it does what you want. The idea is that you should start with a program that does something and make small modifications, debugging them as you go, so that you always have a working program.

For example, Linux is an operating system kernel that contains millions of lines of code, but it started out as a simple program Linus Torvalds used to explore the Intel 80386 chip. According to Larry Greenfield, one of Linus’s earlier projects was a program that would switch between displaying AAAA and BBBB. This later evolved to Linux (The Linux Users’ Guide Beta Version 1).

Later chapters will make more suggestions about debugging and other programming practices.

## Formal and natural languages

Natural languages are the languages that people speak, such as English, Spanish, and French. They were not designed by people (although people try to impose some order on them); they evolved naturally.

Formal languages are languages that are designed by people for specific applications. For example, the notation that mathematicians use is a formal language that is particularly good at denoting relationships among numbers and symbols. Chemists use a formal language to represent the chemical structure of molecules. And most importantly:

Programming languages are formal languages that have been designed to express computations.

Formal languages tend to have strict rules about syntax. For example, 3+3=6 is a syntactically correct mathematical statement, but 3=+6$ is not. H2O is a syntactically correct chemical name, but 2Zz is not. Syntax rules come in two flavors, pertaining to tokens and structure. Tokens are the basic elements of the language, such as words, numbers, parentheses, commas, and so on. In Javascript, a statement like console.log("Happy New Year for ", 2013) has 6 tokens: a function name, an open parenthesis (round bracket), a string, a comma, a number, and a close parenthesis. It is possible to make errors in the way one constructs tokens. One of the problems with 3=+6$ is that $ is not a legal token in mathematics (at least as far as we know). Similarly, 2Zz is not a legal token in chemistry notation because there is no element with the abbreviation Zz. The second type of syntax rule pertains to the structure of a statement—that is, the way the tokens are arranged. The statement 3=+6$ is structurally illegal because you can’t place a plus sign immediately after an equal sign. Similarly, molecular formulas have to have subscripts after the element name, not before. And in our Javascript example, if we omitted the comma, or if we changed the two parentheses around to say console.log)"Happy New Year for ",2013( our statement would still have six legal and valid tokens, but the structure is illegal.

When you read a sentence in English or a statement in a formal language, you have to figure out what the structure of the sentence is (although in a natural language you do this subconsciously). This process is called parsing.

For example, when you hear the sentence, “The other shoe fell”, you understand that the other shoe is the subject and fell is the verb. Once you have parsed a sentence, you can figure out what it means, or the semantics of the sentence. Assuming that you know what a shoe is and what it means to fall, you will understand the general implication of this sentence.

Although formal and natural languages have many features in common—tokens, structure, syntax, and semantics—there are many differences:

## Glossary

ambiguity

Natural languages are full of ambiguity, which people deal with by using contextual clues and other information. Formal languages are designed to be nearly or completely unambiguous, which means that any statement has exactly one meaning, regardless of context.

redundancy

In order to make up for ambiguity and reduce misunderstandings, natural languages employ lots of redundancy. As a result, they are often verbose. Formal languages are less redundant and more concise.

literalness

Formal languages mean exactly what they say. On the other hand, natural languages are full of idiom and metaphor. If someone says, “The other shoe fell”, there is probably no shoe and nothing falling.
You’ll need to find the original joke to understand the idiomatic meaning of the other shoe falling. Yahoo! Answers thinks it knows!

People who grow up speaking a natural language—everyone—often have a hard time adjusting to formal languages. In some ways, the difference between formal and natural language is like the difference between poetry and prose, but more so:

poetry

Words are used for their sounds as well as for their meaning, and the whole poem together creates an effect or emotional response. Ambiguity is not only common but often deliberate.

prose

The literal meaning of words is more important, and the structure contributes more meaning. Prose is more amenable to analysis than poetry but still often ambiguous.

program

The meaning of a computer program is unambiguous and literal, and can be understood entirely by analysis of the tokens and structure.

Here are some suggestions for reading programs (and other formal languages). First, remember that formal languages are much more dense than natural languages, so it takes longer to read them. Also, the structure is very important, so it is usually not a good idea to read from top to bottom, left to right. Instead, learn to parse the program in your head, identifying the tokens and interpreting the structure. Finally, the details matter. Little things like spelling errors and bad punctuation, which you can get away with in natural languages, can make a big difference in a formal language.

## The first program

Traditionally, the first program written in a new language is called Hello, World! because all it does is display the words, Hello, World! In Javascript, the script looks like this: (For scripts, we’ll show line numbers to the left of the Javascript statements.)

console.log("Hello, World!");

This is an example of using console.log, Javascript’s print function, which doesn’t actually print anything on paper. It displays a value on the screen’s console. In this case, the result shown is

Hello, World!

The quotation marks in the program mark the beginning and end of the value; they don’t appear in the result.

Some people judge the quality of a programming language by the simplicity of the Hello, World! program. By this standard, Javascript does about as well as possible.

As programs get bigger and more complicated, they get more difficult to read. Formal languages are dense, and it is often difficult to look at a piece of code and figure out what it is doing, or why.

For this reason, it is a good idea to add notes to your programs to explain in natural language what the program is doing.

A comment in a computer program is text that is intended only for the human reader — it is completely ignored by the interpreter.

In Javascript, the \\ token starts a comment. The rest of the line is ignored. Here is a new version of Hello, World!.

//---------------------------------------------------
// This demo program shows off how elegant Javascript is!
// Based on the Python program by Joe Soap, December 2010.
// Anyone may freely copy or modify this program.
//---------------------------------------------------

console.log("Hello, World!");     // Isn't this easy!

You’ll also notice that we’ve left a blank line in the program. Blank lines are also ignored by the interpreter, but comments and blank lines can make your programs much easier for humans to parse. Use them liberally!

Javascript also supports multiline comments with the /* */ style.

/*
---------------------------------------------------
This demo program shows off how elegant Javascript is!
Based on the Python program by Joe Soap, December 2010.
Anyone may freely copy or modify this program.
---------------------------------------------------
*/

console.log("Hello, World!");     // Isn't this easy!

In addition to adding hints and suggestions for human readers, comments play an important role in debugging. Because the Javascript interpreter doesn’t try to run commented lines, you can “comment out” sections of your code to isolate errors.

console.log("Hello, World!");
// console.log("I am trying to find");
// console.log("out which line");
// console.log("of my code isn't");
// console.log("working the way I expect it to.);

In the above code, only line 1 is interpreted and run as Javascript. The other lines are ignored. To debug this program, we can uncomment one line at a time until we find out which line has the buggy code.

It is so common for programmers to comment out large blocks of code when they are testing their programs, that programmer’s text editors support quickly commenting out sections of code. In repl.it, our online editor for this book, you can simply highlight the lines you want to comment or uncomment and use the Ctrl + / keyboard shortcut. You will see us using this technique in our example videos.

## Turtle Graphics

In the late 1960s, Seymor Papert’s group at MIT introduced LOGO Turtle as a way to teach computer programming to kids. After learning the basic turtle commands (also called an API), you can make surprising computer graphics programs with only a little bit of code.

We’re using a version of Turtle that has been written for Javascript. Thanks to Morgan McGuire at Casual Effects for the code..

As we’ve seen, a program and algorithms consist of a number of commands or statements that execute in an order described by the program. There are many libraries or APIs (application programming interface) that help you useful do things in Javascript. Some APIsread files over a network, others choose random numbers, while others might encrypt data to make it more secure. The turtle API has a number of commands that you can use to move a turtle around a screen and to draw shapes and patterns.

Here’s a short turtle graphics program.

// set up the "pen" color and width
setWidth(30);
setColor("red");

// move forward 100px to draw a red line
fd(100);

wait(1);

// raise the pen "pen up -- pu()", then return the turtle
// to Y coordinate 0 and move it to X coordinate 100
pu();
setY(0);
setX(100)
pd();

wait(1);

// draw a blue line
setColor("blue");
fd(100);

wait(1);

// move turtle to the top left quadrant
pu();
setY(300);
setX(-300)
pd();

// draw a "DeepPink" circle
setColor("DeepPink");
startFill("DeepPink");
arc(360, 80);
endFill();

// hide the turtle
ht();
When we run this program, we draw this image:

Turtle programs use the metaphor of a turtle moving around drawing with a pen. To move the turtle without drawing, you call the “pen up” method, or pu(), as we do on lines 12 and 26. The turtle is plotted on an x,y plane (also called a Cartesian Plane). The x coordinate specifies the horizontal position of the turtle and the y coordinate specifies the vertical position of the turtle. In this plane, (0, 0) is in the middle of the window. Negative x coordinates are to the left of the center, and negative y coordinates are below the center. We call the setX() and setY() methods to move the turtle’s position. If the pen is down, it draws while we move. If it’s up, turtle moves without a trace. Notice how we draw a “DeepPink” circle, starting on line 32? Because our Javascript program executes in a web browser, we can use any of the “named colors” that are part of the web development standard. You can find all of the name colors here.

## Turtle documentation

To fully use the turtle API, you will need to read and understand the documentation. Part of becoming a programmer and thinking like a computer scientist includes the ability to read (and write!) technical documentation. No programmer remembers every possible language feature or available commands. Before you begin the exercises and lab for this chapter, review the full

fd(distance)

Move forward the given distance.

bk(distance)

Move backward the given distance.

rt(angle)

Turn right (clockwise) in place.

rt(angle, radius)

Turn right (clockwise) in an arc of the given radius.

lt(angle)

Turn left (counterclockwise) in place.

lt(angle, radius)

Turn left (counterclockwise) in an arc of the given radius.

arc(angle, radius)

Draw an arc around the turtle, without moving the turtle. The angle is relative to the current heading.

pu()

Pick the pen up to temporarily move without drawing.

pd()

Put the pen down to resume drawing.

ht()

Hide the turtle.

setColor(color)

Set the pen color by name such as RED or CSS color string such as “#FF0041”.

setColor(r, g, b)

Set the pen color based on three RGB values each between zero and one.

setColor(r, g, b, a)

Set the pen color based on three RGB values and an opacity value, each between zero and one.

startFill(color)

Start drawing a filled region of the given color. Must end with endFill()

startFill(r, g, b)

Start drawing a filled region with color given by three RGB values, each between zero and one.

setColor(r, g, b, a)

Start drawing a region filled by three RGB values and an opacity value, each between zero and one.

endFill()

End drawing a filled region and actually fill it. If the pen is down, then the outline will also be stroked.

setPosition(x, y)

Sets the absolute position. If the pen is down, draws a line to that position.

setX(x)

Sets the absolute x-axis position. If the pen is down, draws a line to that position.

getX()

Returns the absolute x-axis position.

setY(x)

Sets the absolute y-axis position. If the pen is down, draws a line to that position.

getY()

Returns the absolute y-axis position.

setWidth(width)

Sets the pen width.

setHeading(degrees)

Sets the current heading in degrees measured clockwise from the upwards vertical axis. North = 0, East = 90, South = 180, West = 270.

getHeading()

Returns the current heading in degrees measured clockwise from the upwards vertical axis. North = 0, East = 90, South = 180, West = 270.

setScale(s)

Scales all distances (but not x and y coordinates or pen width) by this factor. Useful for reusing drawing commands for different size objects. 1.0 is the default scale.

getScale()

Returns the current drawing scale.

setSpeed(speed)

Sets the number of commands executed before showing the next frame of animation. Defaults to 1. Can be set to Infinity to draw the entire image at once. Does not affect wait times.

clear(color)

Clears the screen to the specified color

clear(r, g, b)

Clears the screen to the specified color

wait(seconds)

Pauses drawing for approximately this many seconds. Useful for creating animations. Not affected by setSpeed.

## Turtle Exercises 1

Turtle Exercises 1 Repl

1. Use turtle to draw a red square with a pink border
2. Draw three circles, side-by-side. The first one should be blue, the second green, the third red.
3. Draw a triangle.
4. (bonus) Draw a 5-pointed star. Hint: draw this on a piece of paper first

## First Turtle Lab

First Turtle Lab Repl

Our first lab presents an open-ended exercise, just to get you started. Use turtle graphics to draw a picture. We suggest you spend about one hour working on this lab. Make sure that you includes some commands from the documentation that are not in the example program. Other than that, the content of your drawing is up to you.

## Glossary

algorithm

A set of specific steps for solving a category of problems.

bug

An error in a program.

comment

Information in a program that is meant for other programmers (or anyone reading the source code) and has no effect on the execution of the program.

debugging

The process of finding and removing any of the three kinds of programming errors.

exception

Another name for a runtime error.

formal language

Any one of the languages that people have designed for specific purposes, such as representing mathematical ideas or computer programs; all programming languages are formal languages.

high-level language

A programming language like Javascript that is designed to be easy for humans to read and write.

immediate mode

A style of using Javascript where we type expressions at the command prompt, and the results are shown immediately. Contrast with script, and see the entry under Javascript shell.

interpreter

The engine that executes your Javascript scripts or expressions.

low-level language

A programming language that is designed to be easy for a computer to execute; also called machine language or assembly language.

natural language

Any one of the languages that people speak that evolved naturally.

object code

The output of the compiler after it translates the program.

parse

To examine a program and analyze the syntactic structure.

portability

A property of a program that can run on more than one kind of computer.

print function

A function used in a program or script that causes the Javascript interpreter to display a value on its output device.

problem solving

The process of formulating a problem, finding a solution, and expressing the solution.

program

a sequence of instructions that specifies to a computer actions and computations to be performed.

Javascript console

An interactive user interface to the Javascript interpreter. The user of a Javascript shell types commands at the prompt, and presses the return key to send these commands immediately to the interpreter for processing.

runtime error

An error that does not occur until the program has started to execute but that prevents the program from continuing.

script

A program stored in a file (usually one that will be interpreted).

semantic error

An error in a program that makes it do something other than what the programmer intended.

semantics

The meaning of a program.

source code

A program in a high-level language before being compiled.

syntax

The structure of a program.

syntax error

An error in a program that makes it impossible to parse — and therefore impossible to interpret.

token

One of the basic elements of the syntactic structure of a program, analogous to a word in a natural language.

# Variables, expressions and statements

## Values and data types

A value is one of the fundamental things — like a letter or a number — that a program manipulates. Programming turtle we have been using values like 100 when we write fd(100) and "blue" in statements like setColor("blue").

These values are classified into different classes, or data types: 100 is an number, and "blue" is a string, so-called because it contains a string of letters. You (and the interpreter) can identify strings because they are enclosed in quotation marks.

If you are not sure what class a value falls into, the Javascript typeof operator can tell you.

⠕ typeof "blue";
=> 'string'
⠕ typeof 100;
=> 'number'

Not surprisingly, strings are of type string and integers are of type number. In Javascript, both whole numbers and fractions (numbers with decimal points) are of type number. At this stage, you can treat the words class and type interchangeably. We’ll come back to a deeper understanding of what a class is in later chapters.

⠕ typeof 3.2;
=> 'number'

What about values like "17" and "3.2"? They look like numbers, but they are in quotation marks like strings.

### Strings

⠕ typeof "17";
=> 'string'
⠕ typeof "3.2";
=> 'string'

They’re strings!

Strings in Javascript can be enclosed in either single quotes (') or double quotes ("), or “backticks” ( ).

⠕ typeof 'This is a string.';
=> 'string'
⠕ typeof "And so is this.";
=> 'string'
⠕ typeof and this is a special type of string...;
=> 'string'

Double quoted strings can contain single quotes inside them, as in "Bruce's beard", and single quoted strings can have double quotes inside them, as in 'The knights who say "Ni!"'.

Strings enclosed with the backtick symbol are called template literals. Template literals can contain either single or double quotes:

console.log("Oh no", she exclaimed, "Ben's bike is broken!");
"Oh no", she exclaimed, "Ben's bike is broken!"
⠕

Template literal strings can even span multiple lines:

⠕ let message = This message will
... span several
... lines;
console.log(message);

This message will
span several
lines.

Strings can also be joined use the + token which adds strings together (also called concatenation).

⠕ let message = "This long message will" +
⠕ "... will appear on one line" +
⠕ "... when it's logged to the console.";
console.log(message);

This long message will... will appear on one line... when it's logged to the console.

Javascript doesn’t care whether you use single or double quotes to surround your strings: once it has parsed the text of your program or command, the way it stores the value is identical in all cases, and the surrounding quotes are not part of the value. But when the interpreter wants to display a string, it has to decide which quotes to use to make it look like a string. It usually choose a single quote.


⠕ 'This is a string.'
=> 'This is a string.'
⠕ "And so is this."
=> 'And so is this.'
⠕ This is a string too!
=> 'This is a string too!'

The code examples in this book will use double quotes as the default, and use single quotes and template literals when they make more sense (such as in strings containing double quotes or spanning multiple lines). We will learn more about template strings in the chapter on strings.

When you type a large number, you might be tempted to use commas between groups of three digits, as in 42,000. This is not a legal number in Javascript, and different Javascript interpreters handle it differently. Formal languages are strict, the notation is concise, and even the smallest change might mean something quite different from what you intended.

## Variables

One of the most powerful features of a programming language is the ability to manipulate variables. A variable is a name that refers to a value.

The let keyword declares a new variable and the assignment token, gives a value to a variable:

⠕ let message = "What's up, Doc?";
⠕ let n = 17;
⠕ let pi = 3.14159;

This example declares three variables and assigns them values. The first assigns the string value "What's up, Doc?" to a variable named message. The second gives the number 17 to n, and the third assigns the number 3.14159 to a variable called pi.

The assignment token, =, should not be confused with equals, which uses the token ===. The assignment statement binds a name, on the left-hand side of the operator, to a value, on the right-hand side. This is why you will get an error if you enter:


⠕ let 17 = n;

SyntaxError: unexpected token: numeric literal

Tip: When reading or writing code, say to yourself “n is assigned 17” or “n gets the value 17”. Don’t say “n equals 17”.

A common way to represent variables on paper is to write the name with an arrow pointing to the variable’s value. This kind of figure is called a state snapshot because it shows what state each of the variables is in at a particular instant in time. (Think of it as the variable’s state of mind). This diagram shows the result of executing the assignment statements:

If you ask the interpreter to evaluate a variable, it will produce the value that is currently linked to the variable:

⠕ message
=> 'What's up, Doc?'
⠕ n
=> 17
⠕ pi
=> 3.14159

We use variables in a program to “remember” things, perhaps the current score in the video game. But variables are variable. This means they can change over time, just like the score in a video game. You can assign a value to a variable, and later assign a different value to the same variable.
(This is different from maths. In maths, if you give x the value 3, it cannot change to link to a different value half-way through your calculations!)

⠕ let day = "Thursday"
⠕ day
=> 'Thursday'
⠕ day = "Friday"
⠕ day
=> 'Friday'
⠕ day = 21
⠕ day
=> 21

You’ll notice we changed the value of day three times, and on the third assignment we even made it refer to a value that was of a different type.

A great deal of programming is about having the computer remember things, e.g. The number of missed calls on your phone, and then arranging to update or change the variable when you miss another call.

Variable names and other identifiers can be arbitrarily long. They can contain both letters and digits, but they have to begin with a letter, the dollar sign $, or an underscore _. Remember that case matters. Bruce and bruce are different variables. In Javascript, capital letters are often used in variables that contain multiple words, such as myName or thePriceOfTeaInChina. The underscore character (_) can appear in a name, too. You may see underscores used to separate multiple words, such as my_name or price_of_tea_in_china, but this style is less common in Javascript. Sometimes programmers start variables with underscores or dollar signs to give them special meanings. In this book, all variable names will start with letters. If you give a variable an illegal name, you get a syntax error: ⠕ let 76trombones = "big parade"; unknown: Identifier directly after number ⠕ let typeof = "Computer Science 101"; unknown: Unexpected token 76trombones is illegal because it does not begin with a letter, but what’s wrong with typeof? It turns out that typeof is reserved as one of Javascript’s keywords. Keywords define the language’s syntax rules and structure, and they cannot be used as variable names. Javascript has almost forty keywords (different versions of Javascript have slightly different keywords):  await finally protected break for return case function super catch if switch class implements this const import throw continue in try debugger instanceof typeof default interface var delete let void else new while export package with extends private yield You might want to keep this list handy. If the interpreter complains about one of your variable names and you don’t know why, see if it is on this list. Programmers generally choose names for their variables that are meaningful to the human readers of the program—they help the programmer document, or remember, what the variable is used for. ## Statements A statement is an instruction that the Javascript interpreter can execute. We have mostly seen the assignment statement so far. Some other kinds of statements that we’ll see shortly are while statements, for statements, and if statements. (There are other kinds too!) When you type a statement in the console and hit enter, Javascript executes it. Statements don’t produce any result. ## Evaluating expressions An expression is a combination of values, variables, operators, and calls to functions. If you type an expression at the Javascript prompt, the interpreter evaluates it and displays the result: ⠕ 1 + 1; => 2 ⠕ typeof "hello"; => 'string' In this example typeof is a Javascript operator that returns the type of a variable or literal data operand. The evaluation of an expression produces a value, which is why expressions can appear on the right hand side of assignment statements. A value all by itself is a simple expression, and so is a variable. These examples show the expression and the value they return indicated by =>. ⠕ 17 => 17; ⠕ let y = 3.14; ⠕ let x = typeof "hello"; ⠕ x => 'string' ⠕ y => 3.14 ## Operators and operands Operators are special tokens that represent computations like addition, multiplication and division. The values the operator uses are called operands. The following are all legal Javascript expressions whose meaning is more or less clear: 20+32 hour-1 hour*60+minute minute/60 5**2 (5+9) * (15-7) The tokens +, -, and *, and the use of parenthesis for grouping, mean in Javascript what they mean in mathematics. The asterisk (*) is the token for multiplication, and ** is the token for exponentiation. ⠕ 2 ** 3 => 8 ⠕ 3 ** 2 => 9 When a variable name appears in the place of an operand, it is replaced with its value before the operation is performed. Addition, subtraction, multiplication, and exponentiation all do what you expect. Example: so let us convert 645 minutes into hours: ⠕ let minutes = 645; ⠕ let hours = minutes / 60; ⠕ hours; => 10.75 Oops! In Javascript, the division operator / always yields a floating point (decimal) result. What we might have wanted to know was how many whole hours there are, and how many minutes remain. Javascript provides helpful Math functions to allow us to do this. Math.floor() rounds a number down to the nearest whole number. Its result is always a whole number — and if it has to adjust the number it always moves it to the left on the number line. So Math.floor(6 / 4) yields 1, but Math.floor(-6 / 4) might surprise you! ⠕ 7 / 4; => 1.75 ⠕ Math.floor(7 / 4); => 1 ⠕ let minutes = 645; ⠕ let hours = Math.flor(minutes / 60); ⠕ hours; => 10 ## Type conversion Here we’ll look at some ways to convert data. We call these type converters. The Number.parseInt(arg) function can take a floating point number or a string, and turn it into an whole number. For floating point numbers, it discards the decimal portion of the number — a process we call truncation towards zero on the number line. Let us see this in action: ⠕ Number.parseInt(3.14); => 3 ⠕ Number.parseInt(3.9999); // This doesn't round to the closest int! => 3 ⠕ Number.parseInt(3.0); => 3 ⠕ Number.parseInt(-3.999); // Note that the result is closer to zero => -3 ⠕ Number.parseInt(minutes / 60); => 10 ⠕ Number.parseInt("2345"); // Parse a string to produce an int => 2345 ⠕ Number.parseInt(17); // It even works if arg is already an int => 17 The type converter Number.parseFloat(arg) can a syntactically legal string into a decimal: ⠕ Number.parseFloat("123.45"); => 123.45 The type converter String(arg) turns its argument into a string: ⠕ String(17) => '17' ⠕ String(123.45) => '123.45' ## Order of operations When more than one operator appears in an expression, the order of evaluation depends on the rules of precedence. Javascript follows the same precedence rules for its mathematical operators that mathematics does. The acronym PEMDAS is a useful way to remember the order of operations: 1. P arentheses have the highest precedence and can be used to force an expression to evaluate in the order you want. Since expressions in parentheses are evaluated first, 2 * (3-1) is 4, and (1+1)**(5-2) is 1. You can also use parentheses to make an expression easier to read, as in (minute * 100) / 60, even though it doesn’t change the result. 2. E xponentiation has the next highest precedence, so 2**1+1 is 3 and not 4, and 3*1**3 is 3 and not 27. 3. M ultiplication and both D ivision operators have the same precedence, which is higher than A ddition and S ubtraction, which also have the same precedence. So 2*3-1 yields 5 rather than 4, and 5-2*2 is 1, not 6. 4. Operators with the same precedence are evaluated from left-to-right. In algebra we say they are left-associative. So in the expression 6-3+2, the subtraction happens first, yielding 3. We then add 2 to get the result 5. If the operations had been evaluated from right to left, the result would have been 6-(3+2), which is 1. (The acronym PEDMAS could mislead you to thinking that division has higher precedence than multiplication, and addition is done ahead of subtraction - don’t be misled. Subtraction and addition are at the same precedence, and the left-to-right rule applies.) • An exception to the left-to-right left-associative rule is the exponentiation operator **, so a useful hint is to always use parentheses to force exactly the order you want when exponentiation is involved: ⠕ 2 ** 3 ** 2 // The right-most ** operator gets done first! => 512 ⠕ (2 ** 3) ** 2 // Use parentheses to force the order you want! => 64 The Javascript console in repl.it is great for exploring and experimenting with expressions like this. You can fork this repl to try it: https://repl.it/@mcuringa/ES6-shell ## Operations on strings If a string looks like a number, Javascript while try to automatically convert it to an number in order to execute a mathematical operation. ⠕ let message = "4"; ⠕ message * 2; => 8 ⠕ message ** 2; => 16; If the automatic type conversion fails in a mathematical operation, Javascript returns the special Not a Number value, NaN. ⠕ let message = "Hello, world."; ⠕ message * 2; => NaN Interestingly, the + operator work with strings, but for strings, the + operator represents concatenation, not addition. As we’ve seen, concatenation means joining the two operands by linking them end-to-end. For example: ⠕ let fruit = "banana"; ⠕ let bakedGood = " nut bread"; ⠕ console.log(fruit + bakedGood); The output of this program is banana nut bread. The space before the word nut is part of the string, and is necessary to produce the space between the concatenated strings. Automatic conversion can be tricky and sometimes lead to unexpected results. Consider: ⠕ let age = "24"; ⠕ age - 10; => 14 ⠕ age + 10; => '2410' ## Input There is a built-in function in Javascript for getting input from the user: ⠕ let n = window.prompt("Please enter your name: "); If you run this sample in a repl.it prompt, it will open a dialog window with the message: Please enter your name: The user of the program can type the name and hit enter. When this happens the text that has been entered is returned from the prompt function, and in this case assigned to the variable n. Even if you asked the user to enter their age, you would get back a string like "17". It would be your job, as the programmer, to convert that string into a integer or float before using it, if that was required. ## Composition So far, we have looked at the elements of a program — variables, expressions, statements, and function calls — in isolation, without talking about how to combine them. One of the most useful features of programming languages is their ability to take small building blocks and compose them into larger chunks. For example, we know how to get the user to enter some input, we know how to convert the string we get into a number, we know how to write a complex expression, and we know how to print values. Let’s put these together in a small four-step program that asks the user to input a value for the radius of a circle, and then computes the area of the circle from the formula Firstly, we’ll do the four steps one at a time: let response = window.prompt("What is your radius? "); let r = Number.parseFloat(response); let area = 3.14159 * r**2; console.log("The area is ", area); Now let’s compose the first two lines into a single line of code, and compose the second two lines into another line of code. let r = Number.parseFloat(window.prompt("What is your radius? ")); console.log("The area is ", 3.14159 * r**2); If we really wanted to be tricky, we could write it all in one statement: console.log("The area is ", 3.14159 * Number.parseFloat(window.prompt("What is your radius? "))**2); Such compact code may not be the most understandable for humans, but it does illustrate how we can compose bigger chunks from our building blocks. If you’re ever in doubt about whether to compose code or fragment it into smaller steps, try to make it as simple as you can for the human to follow. My choice would be the first case above, with four separate steps. ## The modulus operator The modulus operator works on integers (and integer expressions) and gives the remainder when the first number is divided by the second. In Javascript, the modulus operator is a percent sign (%). The syntax is the same as for other operators. It has the same precedence as the multiplication operator. ⠕ let q = Math.floor(7 / 3); // This is integer division ⠕ q; => 2 ⠕ let r = 7 % 3 ⠕ r; => 1 So 7 divided by 3 is 2 with a remainder of 1. The modulus operator turns out to be surprisingly useful. For example, you can check whether one number is divisible by another—if x % y is zero, then x is evenly divisible by y. Also, you can extract the right-most digit or digits from a number. For example, x % 10 yields the right-most digit of x (in base 10). Similarly x % 100 yields the last two digits. It is also extremely useful for doing conversions, say from seconds, to hours, minutes and seconds. So let’s write a program to ask the user to enter some seconds, and we’ll convert them into hours, minutes, and remaining seconds. ⠕ let totalSecs = Number.parseInt(window.prompt("How many seconds, in total?")); ⠕ let hours = Math.floor(totalSecs / 3600); ⠕ let secsStillRemaining = totalSecs % 3600; ⠕ let minutes = Math.floor(secsStillRemaining / 60); ⠕ let secsFinallyRemaining = secsStillRemaining % 60; ⠕ ⠕ console.log("Hrs=", hours, " mins=", minutes, "secs=", secsFinallyRemaining); ## Variable Exercises To complete these exercises, open up a Javascript interpreter in repl.it. You can test things out in the right-side interactive window, and write your solutions in the Javascript source file on the left side. You might want to comment out the code you’re not working on, so that the output is less confusing. 1. Take the sentence: All work and no play makes Jack a dull boy. Store each word in a separate variable, then print out the sentence on one line using console.log(). 2. Add parenthesis to the expression 6 * 1 - 2 to change its value from 4 to -6. 3. Start the Javascript interpreter and enter bruce + 4 at the prompt. This will give you an error: ReferenceError: bruce is not defined Assign a value to bruce so that bruce + 4 evaluates to 10. 4. The formula for computing the final amount if one is earning compound interest is given on Wikipedia as Write a Javascript program that assigns the principal amount of$10000 to variable P, assign to n the value 12, and assign to r the interest rate of 8%. Set variable t to be the number of years the money will be compounded for. Calculate and print the final amount after t years.

5. Evaluate the following numerical expressions in your head, then use the Javascript interpreter to check your results:

1. ⠕ 5 % 2
2. ⠕ 9 % 5
3. ⠕ 15 % 12
4. ⠕ 12 % 15
5. ⠕ 6 % 6
6. ⠕ 0 % 7
7. ⠕ 7 % 0

What happened with the last example? Why? If you were able to correctly anticipate the computer’s response in all but the last one, it is time to move on. If not, take time now to make up examples of your own. Explore the modulus operator until you are confident you understand how it works.

6. You look at the clock and it is exactly 2pm. You set an alarm to go off in 51 hours. At what time does the alarm go off? (Hint: you could count on your fingers, but this is not what we’re after. If you are tempted to count on your fingers, change the 51 to 5100.)

7. Write a Javascript program to solve the general version of the above problem. Create a variable hrs to represent the number of hours to wait.
Your program should output what the time will be on the clock when the alarm goes off, regardless of the value that hrs holds.

## Glossary

assignment statement

A statement that assigns a value to a name (variable). To the left of the assignment operator, =, is a name. To the right of the assignment token is an expression which is evaluated by the Javascript interpreter and then assigned to the name. The difference between the left and right hand sides of the assignment statement is often confusing to new programmers. In the following assignment:
n = n + 1
n plays a very different role on each side of the =. On the right it is a value and makes up part of the expression which will be evaluated by the Javascript interpreter before assigning it to the name on the left.

assignment token

= is Javascript’s assignment token. Do not confuse it with equals, which is an operator for comparing values.

composition

The ability to combine simple expressions and statements into compound statements and expressions in order to represent complex computations concisely.

concatenate

To join two strings end-to-end.

data type

A set of values. The type of a value determines how it can be used in expressions. So far, the types you have seen are number and string.

evaluate

To simplify an expression by performing the operations in order to yield a single value.

expression

A combination of variables, operators, and values that represents a single result value.

float

Javascript data type which stores floating-point numbers. Although integers and floats are are all of type number, floating-point numbers are stored internally in two parts: a base and an exponent. When printed in the standard format, they look like decimal numbers. Beware of rounding errors when you use float s, and remember that they are only approximate values.

int

An integer or whole number. In Javascript, its type is number.

keyword

A reserved word that is used by the compiler to parse program; you cannot use keywords like if, function, and while as variable names.

modulus operator

An operator, denoted with a percent sign ( %), that works on integers and yields the remainder when one number is divided by another.

operand

One of the values on which an operator operates.

operator

A special symbol that represents a simple computation like addition, multiplication, or string concatenation.

rules of precedence

The set of rules governing the order in which expressions involving multiple operators and operands are evaluated.

state snapshot

A graphical representation of a set of variables and the values to which they refer, taken at a particular instant during the program’s execution.

statement

An instruction that the Javascript interpreter can execute. So far we have mostly seen the assignment statement.

string

A Javascript data type that holds a string of characters (e.g. textual data).

value

A number or string (or other things to be named later) that can be stored in a variable or computed in an expression.

variable

A name that refers to a value.

variable name

A name given to a variable. Variable names in Javascript consist of a sequence of letters (a..z, A..Z, $, and _) and digits (0..9) that begins with a letter. In best programming practice, variable names should be chosen so that they describe their use in the program, making the program self documenting. # Functions ## Functions In Javascript, a function is a named sequence of statements that belong together. Their primary purpose is to help us organize programs into chunks that match how we think about the problem. The syntax for a function definition is: function NAME( PARAMETERS ) { STATEMENTS } We can make up any names we want for the functions we create, except that we can’t use a name that is a Javascript keyword, and the names must follow the rules for legal identifiers (the same rules that apply to variable names). There can be any number of statements inside the function, but they have to be between the curly braces ({}). These statements make up the function body. In the examples in this book, we will use the standard indentation of two spaces. Function definitions are the second of several compound statements we will see, all of which have the same pattern: 1. A header line which begins with a keyword and ends with an opening (left) curly brace. 2. A body consisting of one or more Javascript statements, each indented the same amount — we will use 2 spaces — from the header line. 3. A closing (right) curly brace. We’ve already seen the for loop which follows this pattern. So looking again at the function definition, the keyword in the header is function, which is followed by the name of the function and some parameters enclosed in parentheses. The parameter list may be empty, or it may contain any number of parameters separated from one another by commas. In either case, the parentheses are required. The parameters specifies what information, if any, we have to provide in order to use the new function. Suppose we are writing a program to calculate the amount of tip due on a bill. We might write a function to “calculate tip”. “calculate tip” is an abstraction, or a mental chunk, of a number of smaller steps. So let’s write a function to capture the pattern of this “building block”: /* Calculate the tip on a bill, given the pct of the tip. */ function calculateTip (bill, pct) { let tip = bill * (pct * .01); // convert pct to a decimal and calculate tip = tip.toFixed(tip, 2); // convert tip to a number with 2 decimal places total = tip + bill; total = Number.parseFloat(total).toFixed(2); // now show the results to the user console.log("Bill amount:$" + bill);
console.log("Tip percentage: " + pct + "%");
console.log("Total amount due: $" + total); } // find the amount of an 18% tip on a$100 bill
calculateTip(100,18);

This function is named calculateTip. It has two parameters: one to tell the function the amount of the bill, and the other to tell it the percent tip to calculate.

Defining a new function does not make the function run. To do that we need a function call. We’ve already seen how to call some built-in functions like console.log, window.input, and Number.parseInt. Function calls contain the name of the function being executed followed by a list of values, called arguments, which are assigned to the parameters in the function definition. So in the last line of the example program above, we call the function, and pass 100 as the amount of the bill and 18 as the percentage of the tip. While the function is executing, then, the variable bill refers to the value 100, and the variable pct refers to 18. We can pass either variables (like myBill) or literal values (like 100) as arguments.

Once we’ve defined a function, we can call it as often as we like, and its statements will be executed each time we call it. In the next example, we calculate 3 different tip amounts for the same bill, using calculateTip defined above.

let myBill = 100;
calculateTip(myBill, 15);
calculateTip(myBill, 18);
calculateTip(myBill, 20);

## Composition: Functions can call other functions

So far, we have looked at the elements of a program—variables, expressions, and statements—in isolation, without talking about how to combine them.

One of the most useful features of programming languages is their ability to take small building blocks and compose them. In our calculateTip example, we call several Javascript built-in functions: toFixed to keep our amounts to 2 decimal places and Number.parseFloat to convert the data to a float so that we can use toFixed. We use console.log to print our output on the Javascript console. As we will see, we can compose our programs of many functions that we define ourselves.

There are some points worth noting here:

• Functions can call other functions.
• A caller of this function might say calculateTip(myBill, 15). The parameters of this function, bill and tip, are assigned the values of the myBill variable, and the number literal 15, respectively.
• In the body of the function they are just like any other variable.

So far, it may not be clear why it is worth the trouble to create all of these new functions. Actually, there are a lot of reasons, but this example demonstrates two:

1. Creating a new function gives us an opportunity to name a group of statements. Functions can simplify a program by hiding a complex computation behind a single command. The function (including its name) can capture our mental chunking, or abstraction, of the problem.
2. Creating a new function can make a program smaller by eliminating repetitive code.

As we might expect, we have to create a function before we can execute it. In other words, the function definition has to be executed before the function is called.

## Flow of execution

In order to ensure that a function is defined before its first use, we have to know the order in which statements are executed, which is called the flow of execution.

Execution always begins at the first statement of the program. Statements are executed one at a time, in order from top to bottom.

Function definitions do not alter the flow of execution of the program, but remember that statements inside the function are not executed until the function is called. In Javascript we can define one function inside another. In this case, the inner definition isn’t executed until the outer function is called.

Function calls are like a detour in the flow of execution. Instead of going to the next statement, the flow jumps to the first line of the called function, executes all the statements there, and then comes back to pick up where it left off.

That sounds simple enough, until we remember that one function can call another. While in the middle of one function, the program might have to execute the statements in another function. But while executing that new function, the program might have to execute yet another function!

Fortunately, Javascript is adept at keeping track of where it is, so each time a function completes, the program picks up where it left off in the function that called it. When it gets to the end of the program, it terminates.

What’s the moral of this sordid tale? When we read a program, don’t read from top to bottom. Instead, follow the flow of execution.

## Functions that require arguments

Most functions require arguments: the arguments provide for generalization, allowing the same function to work with different data inputs. For example, if we want to find the absolute value of a number, we have to indicate what the number is. The Javascript Math class has a built-in function for computing the absolute value:

⠕ Math.abs(5);
=> 5
⠕ Math.abs(-5);
=> 5

In this example, the arguments to the abs function are 5 and -5.

Some functions take more than one argument. For example the function calculateTip function we wrote in the example above takes two arguments: the amount of the bill and the percent tip to calculate. Inside the function, the values that are passed get assigned to variables called parameters.

⠕ calculateTip(87, 10);
Bill amount: $87 Tip percentage: 10% Total amount due:$8.70

Another built-in function that takes more than one argument is Math.max.

⠕ Math.max(7, 11);
=> 11
⠕ Math.max(4, 1, 17, 2, 12);
=> 17
⠕ Math.max(3 * 11, 5**3, 512 - 9, 1024**0);
=> 503

Math.max can be passed any number of arguments, separated by commas, and will return the largest value passed. The arguments can be either simple values or expressions. In the last example, 503 is returned, since it is larger than 33, 125, and 1. All of the expressions are resolved — in this case the mathematical operations are calculated — before their values are assigned to the function parameters.

## Functions that return values

Some functions return values. In the previous section we saw that Math.abs and Math.max return values. calculateTip does not return a value; it uses console.log to produce output on the screen for the user. We can use the return values from functions to compose more complex functions.

A function that returns a value is called a fruitful function in this book. The opposite of a fruitful function is void function — one that is not executed for its resulting value, but is executed because it does something useful. (Languages like Java, C#, C and C++ use the term “void function”, other languages like Pascal call it a procedure.) Even though void functions are not executed for their resulting value, Javascript always wants to return something. So if the programmer doesn’t arrange to return a value, Javascript will automatically return the value undefined.

How do we write our own fruitful function? Let’s look at the standard formula for compound interest as an example of a fruitful function:

/*
Apply the compound interest formula to p
to produce the final amount.
*/
function finalAmt (p, r, n, t) {
let a = p * (1 + r/n) ** (n * t);
// This is new, and makes the function fruitful
return a;
}

//now that we have the function above, let's call it
let toInvest = Number.parseFloat( window.prompt("How much do you want to invest?") );
let fnl = finalAmt(toInvest, 0.08, 12, 5);
console.log("At the end of the period you'll have", fnl);
• The return statement is followed an expression (a in this case). This expression will be evaluated and returned to the caller as the “fruit” of calling this function.
• We prompted the user for the principal amount. The type of toInvest is a string, but we need a number before we can work with it. Javascript can automatically convert it to a number for us when we use it in the calculation. Because it is money, and could have decimal places, we’ve used the Number.parseFloat type converter function to parse the string and return a float.
• Notice how we entered the arguments for 8% interest, compounded 12 times per year, for 5 years.
• When we run this, if we enter 100 when prompted for the amount to invest, we get the output
At the end of the period you’ll have 148.9845708301606
This is a bit messy with all these decimal places, but remember that Javascript doesn’t understand that we’re working with money: it just does the calculation to the best of its ability, without rounding. Later we’ll see how to format the string that is printed in such a way that it does get nicely rounded to two decimal places before printing.
• The line let toInvest = Number.parseFloat( window.prompt("How much do you want to invest?") ); also shows yet another example of composition — we can call a function like Number.parseFloat, and its arguments can be the results of other function calls (like window.prompt) that we’ve called along the way.

Notice something else very important here. The name of the variable we pass as an argument — toInvest — has nothing to do with the name of the parameter — p. It is as if p = toInvest is executed when finalAmt is called. It doesn’t matter what the value was named in the caller, in finalAmt its name is p.

These short variable names are getting quite tricky, so perhaps we’d prefer one of these versions instead:

function finalAmtV2(principalAmount, nominalPercentageRate, numTimesPerYear, years) {
let a = principalAmount * (1 + nominalPercentageRate / numTimesPerYear) ** (numTimesPerYear * years);
return a;
}

function finalAmtV3(amt, rate, compounded, years) {
let a = amt * (1 + rate / compounded) ** (compounded * years);
return a;
}

They all do the same thing. Use your judgment to write code that can be best understood by other humans!
Short variable names are more economical and sometimes make code easier to read: E = mc2 would not be nearly so memorable if Einstein had used longer variable names! If you do prefer short names, make sure you also have some comments to enlighten the reader about what the variables are used for.

When we declare a new local variable inside a function, it only exists inside the function, and we cannot use it outside. For example, consider again this function:


function finalAmt (p, r, n, t) {
let a = p * (1 + r/n) ** (n * t);
return a;
}

If we try to use a, outside the function, we’ll get an error like this:

⠕ a
ReferenceError: a is not defined

The variable a is local to finalAmt, and is not visible outside the function.

Additionally, a only exists while the function is being executed — we call this its lifetime. When the execution of the function terminates, the local variables are destroyed.

Parameters are also local, and act like local variables. For example, the lifetimes of p, r, n, t begin when finalAmt is called, and the lifetime ends when the function completes its execution.

So it is not possible for a function to set some local variable to a value, complete its execution, and then when it is called again next time, recover the local variable. Each call of the function creates new local variables, and their lifetimes expire when the function returns to the caller.

## Glossary

argument

A value provided to a function when the function is called. This value is assigned to the corresponding parameter in the function. The argument can be the result of an expression which may involve operators, operands and calls to other fruitful functions.

body

The second part of a compound statement. The body consists of a sequence of statements all indented the same amount from the beginning of the header. The standard amount of indentation used within the Python community is 4 spaces.

compound statement

A statement that consists of two parts:

1. header - which begins with a keyword determining the statement type, and ends with a colon.
2. body - containing one or more statements indented the same amount from the header.

The syntax of a compound statement looks like this:

keyword ... :
statement
statement ...
flow of execution

The order in which statements are executed during a program run.

frame

A box in a stack diagram that represents a function call. It contains the local variables and parameters of the function.

function

A named sequence of statements that performs some useful operation. Functions may or may not take parameters and may or may not produce a result.

function call

A statement that executes a function. It consists of the name of the function followed by a list of arguments enclosed in parentheses.

function composition

Using the output from one function call as the input to another.

function definition

A statement that creates a new function, specifying its name, parameters, and the statements it executes.

fruitful function

A function that returns a value when it is called.

The first part of a compound statement. A header line begins with a keyword and ends with a colon (:)

import statement

A statement which permits functions and variables defined in another Python module to be brought into the environment of another script. To use the features of the turtle, we need to first import the turtle module.

Variables and objects have lifetimes — they are created at some point during program execution, and will be destroyed at some time.

local variable

A variable defined inside a function. A local variable can only be used inside its function. Parameters of a function are also a special kind of local variable.

parameter

A name used inside a function to refer to the value which was passed to it as an argument.

refactor

A fancy word to describe reorganizing our program code, usually to make it more understandable. Typically, we have a program that is already working, then we go back to “tidy it up”. It often involves choosing better variable names, or spotting repeated patterns and moving that code into a function.

stack diagram

A graphical representation of a stack of functions, their variables, and the values to which they refer.

traceback

A list of the functions that are executing, printed when a runtime error occurs. A traceback is also commonly referred to as a stack trace, since it lists the functions in the order in which they are stored in the runtime stack.

void function

The opposite of a fruitful function: one that does not return a value. It is executed for the work it does, rather than for the value it returns.

## Function Exercises

1. Write a void (non-fruitful) function to that prints out a “hello” message. Your function should declare 3 parameters: firstName, lastName, and title. title will be Mr., Ms., Dr., etc. The function should print a message like this one: Hello Dr. Matthew Curinga.

2. Write a function half(num) which returns the value of num divided by 2.

3. Write a function triple(num) which return num * 3.

4. Write a function areaOfACircle(r) which returns the area of a circle of radius r. For the value of PI, use the constant Math.PI
(Hint: if you can’t remember how to find the area of a circle, look it up or ask a friend.)

5. Write a function hypotenuse(a, b) which calculates the hypotenuse of a right triangle when given the length of sides a and b. Use the Pythagorean theorem a^2 + b^2 = c^2.
Note, you will need to be able to calculate square roots to solve this problem. You can use the build in math function Math.sqrt.

6. (hard bonus) Write a function called distance(x1, y1, x2, y2) which calculates the distance between the point at (x1, y1) and (x2, y2) on a Cartesian Plane. You can find the formula for this at http://www.mathsisfun.com/algebra/distance-2-points.html
Use the hypotenuse function from exercise 5 to compose this function.

## Functions Lab

This is the first “lab” in our textbook. For this project, you will be asked to write a complete program that solves a problem. The labs should break up parts of the program into different functions. Your program should start when the main() function is called. main is not a keyword in Javascript, but in many programming languages there is a convention that the starting function is called main. Please take a look at the Tip Calculator case study below for a sense of how your program should be structured.

For this first lab, too, please pay attention to your coding style to make sure that the program is well formatted and easy for human readers to understand.

For this lab you are going to revisit the lemonade stand estimator from the exercises in chapter 2. You will make an interactive program that asks the user to enter all of the data for:

• prices of the ingredients
• prices for the materials (e.g. cups)
• sale price for a cup of lemonade
• and estimation of the number of cups sold

Once all of the data is entered, the program will print out a neatly formatted message with the results of the estimation.

## Unit testing exercises

For each of these problems, write the unit test first, then write the function. Make sure that it passes the test.

Convert km to m. For example, write a function that converts kilometers to meters, as well as a function that tests this code. There are 1,000 meters in 1 kilometer. The code might look like this:


function kmToM (km) {
let m = km / 1000;
return m;
}

function test_kmToM() {
assert(kmToM(1) === 1000, "1km should = 1000m");
assert(kmToM(52) === 52000, "52km should = 52000m");
assert(kmToM(.05) === 50, ".05km should = 50m");
assert(kmToM(-3) === -3000, "-3 should = -3000m");
assert(kmToM(0) === 0, "0 should = 0");
}
1. Tbs to cups. There are 16 tablespoons in a cup. Write a function that converts Tbs to cups. It should take the number of tablespoons as an argument and return the number of cups.

2. Kilos (kg) to pounds (lbs). Write a function that converts kilograms to pounds. Use the conversion rate of 2.2 pounds for each kilogram.

3. Weight of water. 1 liter of water weighs exactly 1 kilogram. Write a function that has a parameter for the volume of water in liters returns the weight of water in pounds, something like this: function litersOfWaterInLbs(liters)

4. Format currency. Write a function fmtCurrency(amount, symbol) that takes a currency amount as a real number and returns a string, with the currency symbol at the start followed by the amount rounded to 2 decimal places (using toFixed).

5. Making pizza. You make pizzas. When you make the sauce, if you only use 1 can of tomatoes, it’s not enough for the whole pie. You need 1.5 cans per pizza. When you are making a lot of pizzas (and a big pot of sauce), you want a function that tells you how many cans of tomatoes to buy. Of course, you can’t buy half a can of tomatoes, so you must round up if there’s a half can. To “round up”, use Javascript’s built in Math.round function.

### Rounding numbers (optional challenge)

Javascript’s built-in Math.round(n) rounds any real number to the closest integer. Write a more flexible function, round(n, p) that rounds a number n to the number of decimal places specified by p.

Examples:

⠕ round(2.457, 2);
=> 2.46
⠕ round(3.98746144, 4)
=> 3.9875
⠕ round(3.98746144, 0)
=> 4
⠕ round(52, -1)
=> 50
⠕ round(55, -1)
=> 60
⠕ round(542, -2)
=> 540

Your tests should test all of these examples.

## Code Listing 1: The Tip Calculator

### Refactoring

Now that we have fruitful functions, we can focus our attention on reorganizing our code so that it fits more nicely into our mental chunks.
This process of rearrangement is called refactoring the code.

With our Tip Calculator we need to find the amount of the tip and show the results to the user. In the example below, we separate the various functions of the program to make a more complete tip calculator. As you’ll see, we’re starting to build code that is useful. Using functions allows us to make changes to one part of a program without affecting other parts of the program. For example, we can change the welcome message without worrying about breaking our calculations.

The trick about refactoring code is to anticipate which things we are likely to want to change each time we call the function: these should become the parameters, or changeable parts, of the functions we write.

View the “Tip Calculator” repl

### Case Study: Tip Calculator

/**
* tip-calulator.js
* This example program helps the user
* calculate the amount of tip to leave
* on a restaurant bill.
* by Matt Curinga
* 15 Sep 2018
*
*/

/*
Present the user with a welcome message.
*/
function welcome() {

let msg =
-----------------------------------
Welcome to the Tip Calculator
-----------------------------------
;

console.log(msg);

}

/*
Calculate the tip on a bill, given the pct of the tip.
Return the amount of the tip
*/
function calcTip(bill, pct) {
// convert pct to a decimal and calculate
let tip = bill * pct;

// convert the tip to float with 2 decimal places
tip = Number.parseFloat(tip);
return tip;
}

/*
Ask the user to enter the amount of the bill
and return this amount as a <float>
*/
let amt = window.prompt("How much was your total bill?");
amt = Number.parseFloat(amt);

return amt;
}

/*
Allow the user to choose a tip amount from a menu.
*/
let pct = window.prompt("What percent tip do you want to leave?");
// convert the pct from a whole number to a fraction
pct /= 100;
pct = Number.parseFloat(pct).toFixed(2);
return pct;
}

function money(amt) {
let dollars = "$" + Number.parseFloat(amt).toFixed(2); return dollars; } /* Prints a message to the user showing the result of the calculations. */ function showResults(bill, tip, pct) { let total = tip + bill; console.log("Bill amount: " + money(bill) ); // multiply % by 100 to convert back console.log("Tip percentage: " + (pct * 100) + "%" ); console.log("Tip amount due: " + money(tip) ); console.log("Total with tip: " + money(total) ); console.log( ----------------------------------- GOOD BYE ----------------------------------- ); } /* Read in the basic information, calcualte the tip and the share, then dispaly the results to the user. */ function main() { welcome(); let myBill = askBillAmt(); let pct = askTipPct(); let tip = calcTip(myBill, pct); showResults(myBill, tip, pct); } main(); # Conditionals A successful attempt to express logical propositions by symbols, the laws of whose combinations should be founded upon the laws of the mental processes which they represent, would, so far, be a step towards a philosophical language. — George Boole, The Mathematical Analysis of Logic 1847 ## Boolean values and expressions A Boolean value is either true or false. It is named after the British mathematician, George Boole, who first formulated Boolean algebra — some rules for reasoning about and combining these values. This is the basis of all modern computer logic. In Javascript, the two Boolean values are true and false (the capitalization must be exactly as shown), and the Javascript type is ‘boolean’. ⠕ tyepof true; => 'boolean' ⠕ tyepof True; => 'undefined' A Boolean expression is an expression that evaluates to produce a result which is a Boolean value. For example, the operator === tests if two values are equal. It produces (or yields) a Boolean value: ⠕ 5 === (3 + 2); // Is five equal 5 to the result of 3 + 2? => true ⠕ 5 === 6; => false ⠕ let j = "hel"; ⠕ j + "lo" === "hello"; true In the first statement, the two operands evaluate to equal values, so the expression evaluates to true; in the second statement, 5 is not equal to 6, so we get false. The === operator is one of six common comparison operators which all produce a boolean result; here are all six: x === y // Produce true if x is equal to y x !== y // Produce true if x is not equal to y x > y // Produce true if x is greater than y x < y // Produce true if x is less than y x >= y // Produce true if x is greater than or equal to y x <= y // Produce true if x is less than or equal to y Although these operations are probably familiar, the Javascript symbols are different from the mathematical symbols. A common error is to use a single equal sign (=) instead of a triple equal sign (===). Remember that = is an assignment operator and === is a comparison operator. Also, there is no such thing as =< or =>. Like any other types we’ve seen so far, Boolean values can be assigned to variables, printed, etc. ⠕ let age = 18; ⠕ let oldEnoughToGetADrivingLicence = age >= 16; ⠕ console.log(oldEnoughToGetADrivingLicence); true ⠕ typeof oldEnoughToGetADrivingLicence; => 'boolean' ## Logical operators There are three logical operators, and &&, or ||, and not !, that allow us to build more complex Boolean expressions from simpler Boolean expressions. The semantics (meaning) of these operators is similar to their meaning in English. For example, x > 0 && x < 10 produces true only if x is greater than 0 and at the same time, x is less than 10. n % 2 == 0 || n % 3 == 0 is true if either of the conditions are true, that is, if the number n is divisible by 2 or it is divisible by 3. (What do you think happens if n is divisible by both 2 and by 3 at the same time? Will the expression yield true or false? Try it in your Javascript interpreter.) Finally, the not operator negates a Boolean value, so ! (x > y) is true if (x > y) is false, that is, if x is less than or equal to y. The expression on the left of the || operator is evaluated first: if the result is true, Javascript does not (and need not) evaluate the expression on the right — this is called short-circuit evaluation. Similarly, for the && operator, if the expression on the left yields false, Javascript does not evaluate the expression on the right. So there are no unnecessary evaluations. ## Truth Tables A truth table is a small table that allows us to list all the possible inputs, and to give the results for the logical operators. Because the && and || operators each have two operands, there are only four rows in a truth table that describes the semantics of &&. a b a && b False False False False True False True False False True True True In a Truth Table, we sometimes use T and F as shorthand for the two Boolean values: here is the truth table describing ||: a b a || b F F F F T T T F T T T T The third logical operator, !, only takes a single operand, so its truth table only has two rows: a !a F T T F ## Simplifying Boolean Expressions A set of rules for simplifying and rearranging expressions is called an algebra. For example, we are all familiar with school algebra rules, such as: n * 0 === 0 which provides rules for working with Boolean values. First, the && operator: x && false === false false && x === false y && x === x && y x && true === x true && x === x x && x === x Here are some corresponding rules for the || operator: x || false === x false || x === x y || x === x || y x || true === true true || x === true x || x === x Two ! operators cancel each other: !(!x) === x ## Conditional execution In order to write useful programs, we almost always need the ability to check conditions and change the behavior of the program accordingly. Conditional statements give us this ability. The simplest form is the if statement: if (x % 2 == 0) { console.log(x, " is even."); console.log("Did you know that 2 is the only even number that is prime?"); } else { console.log(x, " is odd.") ; console.log("Did you know that multiplying two odd numbers always gives an odd result?"); } If it is true, then all the indented statements get executed. If not, then all the statements indented under the else clause get executed. The syntax for an if statement looks like this: if BOOLEAN EXPRESSION { STATEMENTS_1 // Executed if condition evaluates to true } else { STATEMENTS_2 // Executed if condition evaluates to false } As with the function definition from the last chapter and other compound statements like for, the if statement consists of a header line and a body. The header line begins with the keyword if followed by a Boolean expression and ends with a left curly brace ( { ). The indented statements that follow are called a block. The block ends with the right curly brace ( } ). Each of the statements inside the first block of statements are executed in order if the Boolean expression evaluates to true. The entire first block of statements is skipped if the Boolean expression evaluates to false, and instead all the statements indented under the else clause are executed. There is no limit on the number of statements that can appear under the two clauses of an if statement, but there has to be at least one statement in each block. ## Omitting the else clause Another form of the if statement is one in which the else clause is omitted entirely. In this case, when the condition evaluates to true, the statements are executed, otherwise the flow of execution continues to the statement after the if. if (x < 0) { console.log("The negative number ", x, " is not valid here."); x = 42; console.log("I've decided to use the number 42 instead."); } console.log("The square root of ", x, "is", Math.sqrt(x)) ; In this case, the print function that outputs the square root is the one after the if — it comes after our curly braces ended the conditional block. Notice that else is not a statement. The if statement has two clauses, one of which is the (optional) else clause. However you can never use the else keyword outside of an if statement. ## Chained conditionals Sometimes there are more than two possibilities and we need more than two branches. One way to express a computation like that is a chained conditional: if (x < y) { STATEMENTS_A } else if (x > y) { STATEMENTS_B } else { STATEMENTS_C } Again, exactly one branch will be executed. There is no limit of the number of else if statements but only a single (and optional) final else statement is allowed and it must be the last branch in the statement: if (choice === "a") { functionOne(); } else if (choice == "b") { functionTwo(); } else if (choice === "c") { functionThree(); } else { console.log("Invalid choice."); } Each condition is checked in order. If the first is false, the next is checked, and so on. If one of them is true, the corresponding branch executes, and the statement ends. Even if more than one condition is true, only the first true branch executes. ## Nested conditionals One conditional can also be nested within another. (It is the same theme of composability, again!) We could have written the previous example as follows: if (x < y) { STATEMENTS_A } else { if(x > y) { STATEMENTS_B } else { STATEMENTS_C } } The outer conditional contains two branches. The second branch contains another if statement, which has two branches of its own. Those two branches could contain conditional statements as well. Although the indentation of the statements makes the structure apparent, nested conditionals very quickly become difficult to read. In general, it is a good idea to avoid them when we can. Logical operators often provide a way to simplify nested conditional statements. For example, we can rewrite the following code using a single conditional: if (0 < x) { // Assume x is a number here if (x < 10) { console.log("x is a positive single digit."); } } The console.log function is called only if we make it past both the conditionals, so instead of the above which uses two if statements each with a simple condition, we could make a more complex condition using the && operator. Now we only need a single if statement: if (0 < x && x < 10) { console.log("x is a positive single digit."); } ## The return statement The return statement, with or without a value, depending on whether the function is fruitful or void, allows us to terminate the execution of a function before (or when) we reach the end. One reason to use an early return is if we detect an error condition: function printSquareRoot(x) { if (x <= 0) { console.log("Positive numbers only, please."); return; } console.log("The square root of", x, "is", result) } The function printSquareRoot has a parameter named x. The first thing it does is check whether x is less than or equal to 0, in which case it displays an error message and then uses return to exit the function. The flow of execution immediately returns to the caller, and the remaining lines of the function are not executed. ## Truthy evaluations As you integrate Boolean logic into your programs, you will often encounter the pattern where you test if a single value evaluates to true or false. The Boolean condition can be written without a comparison operator because the value itself will be resolves to true or false. if (email) { // send an email... } Any value that is not false, undefined, null, 0, NaN, or an empty string (’’) actually returns true when tested as a conditional statement. Consider the following code: let first = "Diego"; let last = ""; let email = "diego@example.com"; if (email) { // this block will be executed because email console.log("Email evaluted to true"); } if (email === true) { // this block won't be executed because email is not equal to true console.log("Email doesn't equal true"); } if (!last) { // this block (using not) executes // because last is an empty string, it evaluates to false console.log("Enter your last name!"); } In the above example we can say that email is truthy because it evaluates to true even though it doesn’t equal true. Likewise, last is falsy — it evaluates to false because it’s an empty string, not equal to false. ## Logical opposites Each of the six relational operators has a logical opposite: for example, suppose we can get a driving license when our age is greater or equal to 16, we can not get the driving license when we are less than 16. Notice that the opposite of >= is <. operator logical opposite === !== !== === < >= <= > > <= >= < Understanding these logical opposites allows us to sometimes get rid of ! operators. ! operators are often quite difficult to read in computer code, and our intentions will usually be clearer if we can eliminate them. For example, if we wrote this Javascript: if (!(age >= 16)) { console.log("Hey, you're too young to get a driving license!"); } it would probably be clearer to use the simplification laws, and to write instead: if (age < 16) { console.log("Hey, you're too young to get a driving license!") } Two powerful simplification laws (called de Morgan’s laws) that are often helpful when dealing with complicated Boolean expressions are: !(x && y) === (!x) || (!y) !(x || y) === (!x) && (!y) For example, suppose we can slay the dragon only if our magic lightsabre sword is charged to 90% or higher, and we have 100 or more energy units in our protective shield. We find this fragment of Javascript code in the game: if !((swordCharge >= 0.90) && (shieldEnergy >= 100)) { console.log("Your attack has no effect, the dragon fries you to a crisp!"); } else { console.log("The dragon crumples in a heap. You rescue the gorgeous prince!"); } de Morgan’s laws together with the logical opposites would let us rework the condition in a (perhaps) easier to understand way like this: if (swordCharge < 0.90) || (shieldEnergy < 100) { console.log("Your attack has no effect, the dragon fries you to a crisp!"); } else { console.log("The dragon crumples in a heap. You rescue the gorgeous prince!"); } We could also get rid of the ! by swapping around the then and else parts of the conditional. So here is a third version, also equivalent: if (swordCharge >= 0.90) and (shieldEnergy >= 100) { console.log("The dragon crumples in a heap. You rescue the gorgeous prince!"); } else { console.log("Your attack has no effect, the dragon fries you to a crisp!"); } This last version is probably the best of the three, because it very closely matches the initial English statement. Clarity of our code (for other humans), and making it easy to see that the code does what we expect should always be a high priority. As our programming skills develop we’ll find we have more than one way to solve any problem. So good programs are designed. We make choices that favor clarity, simplicity, and elegance. The job title software architect says a lot about what we do — we are architects who engineer our products to balance beauty, functionality, simplicity and clarity in our creations. ## Glossary block A group of consecutive statements with the same indentation. body The block of statements in a compound statement that follows the header. Boolean algebra Some rules for rearranging and reasoning about Boolean expressions. Boolean expression An expression that is either true or false. Boolean value There are exactly two Boolean values: true and false. Boolean values result when a Boolean expression is evaluated by the Javascript interpreter. They have type 'boolean'. branch One of the possible paths of the flow of execution determined by conditional execution. chained conditional A conditional branch with more than two possible flows of execution. In Javascript chained conditionals are written with if ... else if ... else statements. comparison operator Javascript operators that compare two values: ===, !==, >, <, >=, and <=. condition The Boolean expression in a conditional statement that determines which branch is executed. conditional statement A statement that controls the flow of execution depending on some condition. In Javascript the keywords if, else if, and else are used for conditional statements. logical operator One of the operators that combines Boolean expressions: (and) &&, (or) ||, and (not) !. nesting One program structure within another, such as a conditional statement inside a branch of another conditional statement. prompt A visual cue that tells the user that the system is ready to accept input data. truth table A concise table of Boolean values that can describe the semantics of an operator. type conversion An explicit function call that takes a value of one type and computes a corresponding value of another type. wrapping code in a function The process of adding a function header and parameters to a sequence of program statements is often referred to as “wrapping the code in a function”. This process is very useful whenever the program statements in question are going to be used multiple times. It is even more useful when it allows the programmer to express their mental chunking, and how they’ve broken a complex problem into pieces. ## Conditional Exercises You can use this repl for your exercises 1. Assume the days of the week are numbered 0,1,2,3,4,5,6 from Sunday to Saturday. Write a function which is given the day number, and it returns the day name (a string). 2. You go on a wonderful vacation leaving on day number 3 (a Wednesday). You return home after 22 nights sleep. What day of the week is it? Write a general version of the program which asks for the starting day number, and the length of your stay, and it will tell you the name of day of the week you will return on. You might want to use the % mod operator. You can compose this function from the one you wrote in exercise 1. 3. Give the logical opposites of these conditions 1. a > b 2. a >= b 3. a >= 18 and day == 3 4. a >= 18 and day != 3 4. What do these expressions evaluate to? 1. 3 === 3 2. 3 !== 3 3. 3 >= 4 4. !(3 < 4) 5. Write a function which is given an exam score, and it returns a string — the letter grade for that mark — according to this scheme: Score Grade 90-100 A 80-89 B 70-79 C 65-69 D <65 F 6. (hard bonus) Write a function isRightAngled which, given the length of three sides of a triangle, will determine whether the triangle is right-angled. Assume that the third argument to the function is always the longest side. It will return true if the triangle is right-angled, or false otherwise. Hint: Floating point arithmetic is not always exactly accurate, so it is not safe to test floating point numbers for equality. If a good programmer wants to know whether x is equal or close enough to y, they would probably code it up as: if (Math.abs(x-y) < 0.000001) { // x is approximately equal to y }  If you’re intrigued by why floating point arithmetic is sometimes inaccurate, on a piece of paper, divide 10 by 3 and write down the decimal result. You’ll find it does not terminate, so you’ll need an infinitely long sheet of paper. The representation of numbers in computer memory or on your calculator has similar problems: memory is finite, and some digits may have to be discarded, so small inaccuracies creep in. Try this script: let a = Math.sqrt(2.0); console.log(a, a*a); console.log(a*a === 2.0); ## Conditionals Lab This section describes three lab assignments that ask you to write larger programs that are organized into several functions. To complete these labs you will combine what you have learned about variables and expressions, functions, and conditional Boolean expressions. ### Lab 1: BMI Calculator Lab Body Mass Index (BMI) is a ratio of weight to height (squared) that public health and other organizations use as a guide for healthy weights. It is expressed as $\frac{mass}{height^{2}} =BMI$ In this lab you will write a BMI calculator that asks the user for their age, height, and weight. You will calculate their BMI and then report a message indicating if they are at risk for being underweight, healthy weight, overweight, or obese. BMI can be calculated using metric or SI measurements for height and weitht. The standard index comes from metric units: $\frac{mass(kg)}{(height(m))^{2}} = BMI$ If you choose to use SI rather than metric measurements, you can use inches as the units for height and pounds as the unit for weight, and then convert the result by multiplying by the constant 703. The formula would be: $\frac{mass(lbs)}{(height(in))^{2}} \times 703 = BMI$ BMI for children and teens is more complicated, so you will not calculate it for this lab. Instead, if the age is < 20, you should show the user a message that indicates that your calculator is only for adults. Once you have calculated the user’s BMI, you should use the following chart to determine which weight category they are in. Use this table: BMI Category < 18.5 underweight 18.5-24.9 normal weight 25-29.9 overweight > 29.9 obese ### Lab 2: Simplified Chinese Birth Animals Chinese animal signs are determined based on the year of birth and repeat on a 12 year cycle. For this lab, we are going to write a program that asks the user the year they were born and then tells them their animal sign. We will use a simplified version of the calendar which matches animal-year to the Western calendar year. Use the table below for the starting years (and then each animal repeats 12 years later). You will want to use the mod % operator for this problem. Animal Birth Year Rat 1924 Ox 1925 Tiger 1926 Rabbit 1927 Dragon 1928 Snake 1929 Horse 1930 Goat 1931 Monkey 1932 Rooster 1933 Dog 1934 Pig 1935 ### Lab 3: Bouncing turtle This may be an interesting problem if you are comfortable with geometry and trigonometry. In this lab you’ll revisit the randomWalk program that we worked on in our turtle graphics. In the randomWalk the turtle moves in a loop where it chooses a random angle to turn and a random distance for each iteration of the loop. You will modify randomWalk so that the turtle “bounces” when it reaches the edge of the screen. By bounce, the turtle should advance to the edge of the screen (aka canvas) and then turn to the angle of reflection away from the edge. To finish its “walk”, it should then move forward for whatever distance remains for this iteration. Some hints: https://repl.it/@mcuringa/Random-Walk • Determine the maximum and minimum x and y that allow the turtle to stay on the screen. The turtle canvas dimensions are 1920 x 1280 • Before the turtle moves forward, you will have to calculate the ending x, y and determine if it’s on the screen or off the screen • you will need to use getHeading() to make this calculation • you will need to use the trigonometry functions in the Javascript Math library # Iteration with for loops ## Running loops Computers are often used to automate repetitive tasks. Repeating identical or similar tasks without making errors is something that computers do well and people do poorly. Repeated execution of a set of statements is called iteration. Because iteration is so common, Javascript provides several language features to make it easier. The for loop is the form of iteration you’ll likely be using most often, and we will look at that first. In the next chapter we’ve going to look at the while statement — another way to have your program repeat code. After you understand both for and while loops, you will be able to use them both to solve problems. ## The for loop A basic building block of all programs is to be able to repeat some code, over and over again. Javascript’s for loop solves this for us. The syntax for the for loop is: for ([initialization]; [loop condition]; [final-expression]) { loop body } We can see that for follows the familiar pattern for block statements that we have already seen for functions and if/else statements, with a header and then body between opening and closing curly braces ({}); In the case of for, the header contains 3 statements inside the parenthesis. 1. The initialization statement is called exactly once: the first time the program reaches the for statement. 2. The loop condition is tested before each iteration of the loop. If true, the loop body executes. The loop body may contain any number of Javascript statements. 3. After the loop body statements are executed, the final expression is called. Typically this expression increments (adds to) or decrements (subtracts from) the loop variable. After the final expression is called, the loop condition is checked again to see if the loop should continue or terminate. We have already played around with the for loop with our turtle graphics when we were looking at the variables in a spiral. Let’s take a closer look at this function which contains a for loop. function spiral () { setColor("deeppink") let distance = 2; let angle = 91; for (let i=0; i<500; i++) { fd(distance); distance += 2; rt(angle); } } • The variable i in the for statement at line 5 is the loop variable. We could have chosen any other variable name instead, but i is a common convention, being short for the loop index. • The loop initialization assigns the loop variable its starting value: let i = 0; • The indented lines between the curly braces form the loop body. spiral’s loop body contains 3 statements which (line 5) move the turtle forward, (line 6) increment the distance variable, and (line 7) rotate the turtle. • At the beginning of each iteration or pass of the loop, the Javascript interpreter checks the loop condition. If true the loop runs for another iteration. If false, the loop terminates. • At the end of each execution of the body of the loop, Javascript returns to the for header to run the final expression. The final expression here increments i by one, using the special ++ operator. • Finally, when the loop condition is false, the program continues beyond the closing curly brace. In spiral, since there are no other statements in the function body, the function returns undefined since it is a void function. ## Assignment As we have mentioned previously, it is legal to make more than one assignment to the same variable. A new assignment makes an existing variable refer to a new value (and stop referring to the old value). let airTimeRemaining = 15; console.log(airTimeRemaining); airTimeRemaining = 7; console.log(airTimeRemaining); The output of this program is: 15 7 because the first time airTimeRemaining is printed, its value is 15, and the second time, its value is 7. It is especially important to distinguish between an assignment statement and a Boolean expression that tests for equality. Because Javascript uses the equal token (=) for assignment, it is tempting to interpret a statement like a = b as a Boolean test. Unlike mathematics, it is not! Remember that the Javascript token for the equality operator is ===. Note too that an equality test is symmetric, but assignment is not. For example, if a === 7 then 7 === a. But in Javascript, the statement a = 7 is legal and 7 = a is not. In Javascript, an assignment statement can make two variables equal, but because further assignments can change either of them, they don’t have to stay that way: let a = 5; let b = a; // After executing this line, a and b are now equal a = 3; // After executing this line, a and b are no longer equal The third line changes the value of a but does not change the value of b, so they are no longer equal. (In some programming languages, a different symbol is used for assignment, such as <- or :=, to avoid confusion. Some people also think that variable was an unfortunate word to choose, and instead we should have called them assignables. Javascript chooses to follow common terminology and token usage, also found in languages like C, C++, Java, and C#, so we use the tokens = for assignment, == (or === which we prefer in Javascript) for equality, and we talk of variables. ## Updating variables When an assignment statement is executed, the right-hand side expression (i.e. the expression that comes after the assignment token) is evaluated first. This produces a value. Then the assignment is made, so that the variable on the left-hand side now refers to the new value. One of the most common forms of assignment is an update, where the new value of the variable depends on its old value. Deduct 40 cents from my airtime balance, or add one run to the scoreboard. let n = 5; n = 3 * n + 1; Line 2 means get the current value of n, multiply it by three and add one, and assign the answer to n, thus making n refer to the value. So after executing the two lines above, n will point/refer to the integer 16. If you try to get the value of a variable that has never been assigned to, you’ll get an error: ⠕ let w = x + 1; ReferenceError: x is not defined Before you can update a variable, you have to initialize it to some starting value, usually with a simple assignment: let runsScored = 0; ... runsScored = runsScored + 1; Line 3 — updating a variable by adding 1 to it — is very common. It is called an increment of the variable; subtracting 1 is called a decrement. Sometimes programmers also talk about bumping a variable, which means the same as incrementing it by 1. ## Abbreviated assignment Incrementing a variable is so common that Javascript provides an abbreviated syntax for it: ⠕ count = 0; ⠕ count++; ⠕ count; 1 count++ is an abreviation for count = count + 1. We pronounce the operator as “plus-plus”. Javascript offers a different operator (+= pronounced “plus-equals”) for increment values other than 1: ⠕ n = 2; ⠕ n += 5; ⠕ n; 7 There are similar abbreviations for --, -=, *=, /=, and %=: ⠕ n = 3; ⠕ n--; ⠕ n; 2 ⠕ n *= 5; ⠕ n; 10 ⠕ n -= 4; ⠕ n; 6 ⠕ n %= 5; ⠕ n; 1 ## Tables One of the things loops are good for is generating tables. Before computers were readily available, people had to calculate logarithms, sines and cosines, and other mathematical functions by hand. To make that easier, mathematics books contained long tables listing the values of these functions. Creating the tables was slow and boring, and they tended to be full of errors. When computers appeared on the scene, one of the initial reactions was, “This is great! We can use the computers to generate the tables, so there will be no errors.” That turned out to be true (mostly) but shortsighted. Soon thereafter, computers and calculators were so pervasive that the tables became obsolete. Well, almost. For some operations, computers use tables of values to get an approximate answer and then perform computations to improve the approximation. In some cases, there have been errors in the underlying tables, most famously in the table the Intel Pentium processor chip used to perform floating-point division. Although a log table is not as useful as it once was, it still makes a good example of iteration. The following program outputs a sequence of values in the left column and 2 raised to the power of that value in the right column: for (let i=0; i<13; i++) { // Generate numbers 0 to 12 console.log(i + "\t" + 2**i); } The string "\t" represents a tab character. The backslash character in "\t" indicates the beginning of an escape sequence. Escape sequences are used to represent invisible characters like tabs and newlines. The sequence \n represents a newline, breaking a string onto the next line. An escape sequence can appear anywhere in a string; in this example, the tab escape sequence is the only thing in the string. How do you think you represent a backslash in a string? As characters and strings are displayed on the screen, an invisible marker called the cursor keeps track of where the next character will go. After calling console.log, the cursor normally goes to the beginning of the next line. The tab character shifts the cursor to the right until it reaches one of the tab stops. Tabs are useful for making columns of text line up, as in the output of the previous program: 0 1 1 2 2 4 3 8 4 16 5 32 6 64 7 128 8 256 9 512 10 1024 11 2048 12 4096 Because of the tab characters between the columns, the position of the second column does not depend on the number of digits in the first column. ## Two-dimensional tables A two-dimensional table is a table where you read the value at the intersection of a row and a column. A multiplication table is a good example. Let’s say you want to print a multiplication table for the values from 1 to 6. A good way to start is to write a loop that prints the multiples of 2, all on one line. Because console.log moves the cursor to the next line, we’re going to accumulate our data into a string variable, and then print out the whole row with a call to console.log. let row = ""; for (let i=1; i<7; i++) { row += (2 * i) + "\t"; } console.log(row); Here we initialized our loop variable i to 1 rather than 0 because we want to start counting from 1. As the loop executes, the value of i changes from 1 to 6. When i is incremented to 7, the loop terminates. Each time through the loop, it displays the value of 2 * i, followed by the tab escape character. We use the += operator to concatenate each value of i * 2 to the string row. After our for statement terminates, we print the results with console.log. The output of the program is: 2 4 6 8 10 12 So far, so good. The next step is to encapsulate and generalize. ## Encapsulation and generalization Encapsulation is the process of wrapping a piece of code in a function, allowing you to take advantage of all the things functions are good for. You have already seen some examples of encapsulation, including including the square function for our turtle graphics. Generalization means taking something specific, such as printing the multiples of 2, and making it more general or abstract, such as printing the multiples of any integer. We can use function parameters to accomplish generalization and abstraction. This function encapsulates the previous loop and generalizes it to print multiples of n: function printMultiples (n) { let row = ""; for (let i=1; i<7; i++) { row += (n * i) + "\t"; } console.log(row); } To encapsulate, all we had to do was add the first line, which declares the name of the function and the parameter list. To generalize, all we had to do was replace the value 2 with the parameter n. If we call this function with the argument 2, we get the same output as before. With the argument 3, the output is: 3 6 9 12 15 18 With the argument 4, the output is: 4 8 12 16 20 24 By now you can probably guess how to print a multiplication table — by calling printMultiples repeatedly with different arguments. In fact, we can use another loop: for (let i=1; i<7; i++) { printMultiples(i); } Notice how similar this loop is to the one inside printMultiples. All we did was replace the print function with a function call. The output of this program is a multiplication table: 1 2 3 4 5 6 2 4 6 8 10 12 3 6 9 12 15 18 4 8 12 16 20 24 5 10 15 20 25 30 6 12 18 24 30 36 ## More encapsulation and generalization To demonstrate encapsulation again, let’s take the code from the last section and wrap it up in a function: function printMultTable () { for (let i=1; i<7; i++) { printMultiples(i); } } With our printMultTable we encapsulate the code for printing the multiplication table. This process is a common development plan. We develop code by writing lines of code outside any function, or typing them in to the interpreter. When we get the code working, we extract it and wrap it up in a function. This development plan is particularly useful if you don’t know how to divide the program into functions when you start writing. This approach lets you design as you go along. ## Local variables You might be wondering how we can use the same variable, i, in both printMultiples and printMultTable. Doesn’t it cause problems when one of the functions changes the value of the variable? The answer is no, because the i in printMultiples and the i in printMultTable are not the same variable. Variables declared with let inside a function definition are local; you can’t access a local variable from outside its home function. That means you are free to have multiple variables with the same name as long as they are not in the same function. It is common and perfectly legal to have different local variables with the same name. In particular, names like i and j are used frequently as loop variables. If you avoid using them in one function just because you used them somewhere else, you will probably make the program harder to read. ## More generalization As another example of generalization, imagine you wanted a program that would print a multiplication table of any size, not just the six-by-six table. You could add a parameter to printMultTable: function printMultTable (high) { for (let i=1; i <= high; i++) { printMultiples(i); } } We replaced the loop condition i<7 to use the parameter high. Because we want to print upt to and including high, we changed the Boolean operator from < to <=. If we call printMultTable with the argument 7, it displays: 1 2 3 4 5 6 2 4 6 8 10 12 3 6 9 12 15 18 4 8 12 16 20 24 5 10 15 20 25 30 6 12 18 24 30 36 7 14 21 28 35 42 This is fine, except that we probably want the table to be square — with the same number of rows and columns. We have high number of rows, but our old version of printMultiples stops at the literal value <7. To do improve our code, we add another parameter to printMultiples to specify how many columns the table should have. Just to be annoying, we call this parameter high, demonstrating that different functions can have parameters with the same name (just like local variables). Here’s the whole program: function printMultiples (n, high) { let row = ""; for (let i=1; i <= high; i++) { row += (n * i) + "\t"; } console.log(row); } function printMultTable (high) { for (let i=1; i <= high; i++) { printMultiples(i, high); } } Notice that when we added a new parameter, we had to change the first line of the function (the function heading), and we also had to change the place where the function is called in printMultTable. Now, when we call printMultTable(7): 1 2 3 4 5 6 7 2 4 6 8 10 12 14 3 6 9 12 15 18 21 4 8 12 16 20 24 28 5 10 15 20 25 30 35 6 12 18 24 30 36 42 7 14 21 28 35 42 49 ## Solving problems with for loops The for loop is a definite loop – a type of iteration where the number of iterations is (typically) known when the loop begins. In the examples we’ve looked at, we’ve used it to iterate over a range of numbers – to execute the loop a set number of times. In later chapters we’ll learn how to use the for loop to iterate over lists of items as well. We can use a for loop to search through one of these lists, whether a range of numbers or a list of items. For now, we’ll stick with ranges of numbers. Let’s say we want to write a function that counts the multiples of 3 in a range of numbers. We already learned how to use the if statement to test a condition. In this chapter we looked at ways to iterate over a range of numbers. We can combine these techniques to solve our problem. function countMultiplesOf3 (start, end) { let count = 0; for (let i=start; i <= end; i++) { if (i % 3 === 0) { count++; } } return count; } console.log(countMultiplesOf3(3, 12)); // the multiples are [3, 6, 9, 12], so prints 4 In the example above, we test to see if a number is evenly divisible by 3 (i.e. a multiple of 3) using the % mode operator. We use the count variable to keep track of all of the multiples we find, using the ++ operator to increment count each time we find a multiple in our loop. Sometimes we want to exit a for loop early. One way to do this is with a return statement. Let’s write a simple function to test if a number is prime. A prime number is a positive integer greater than 1 that is only divisible by itself and by 1. To test if a number is prime, we will test all of the numbers smaller than it. If any of those numbers divide evenly into the number, it’s not prime. If our loop completes without finding a divisor, our number must be prime. Here’s the code: function isPrime (n) { if (n < 2) { return false; } if (n === 2) { return true; } for (let i = 2; i<n; i++) { if (n % i === 0) { return false; } } return true; } On line 3, we make sure that n is a positive integer greater than 1. On line 6, we handle the special case of 2 – the only even prime. On line 11 we begin our for loop. We do at most enough iterations to check all of the numbers between 2 and n - 1. If we find a divisor of n on line 12, then we return false because n can’t be prime. We don’t need to continue our for loop, so we exit early with a return statement. If we finally reach line 17, we return true. Because of the logic of our program, n must be prime. ## Functions A few times now, we have mentioned all the things functions are good for. By now, you might be wondering what exactly those things are. Here are some of them: 1. Capturing your mental chunking. Breaking your complex tasks into sub-tasks, and giving the sub-tasks a meaningful name is a powerful mental technique. 2. Dividing a long program into functions allows you to separate parts of the program, debug them in isolation, and then compose them into a whole. 3. Functions facilitate the use of iteration. 4. Well-designed functions are often useful for many programs. Once you write and debug one, you can reuse it in many different programs and contexts. ## Glossary control flow The execution and sequencing of statements in a computer program. Statements flow in the order they are written. Selection of certain statements – and exclusion of others – can be accomplished with if and else statements. Repetition of statements is accomplished by iteration, such as with a for loop. definite loop A form of iteration when the (maximum) number of loops are known before the loop begins. encapsulation Encapsulation in computer programming involves writing functionality in code that is isolated from other parts of the program. We can wrap parts of our code in a function to encapsulate it. This allows us to test and validate the encapsulated function independently from other parts of the program. for loop The for loop is a finite loop that repeats the loop body a known number of times. for loops are useful for repeating things a set number of times (e.g. do this 100 times, print all of the odd numbers to 5,000), and iterating through items on a list (e.g. send an email to the whole class roster). loop body Any number of statements that are executed during iterations of the loop. The loop body follows the loop header and is indicated by curly braces and (in well formatted code) one level of indentation. loop initialization The first statement in the loop header parenthesis, typically initializes a loop variable that will be used to test the loop condition. loop variable The loop variable determines when the loop terminates in a Booleaen expression in the loop condition. Often it counts the number of iterations in a loop, but it is modified by the final expression and may be modified in the loop body. reassignment The ability of variables to be given (assigned) a new value after they have been declared. ## For Loop Exercises Fork this repl with empty function definitions to get started 1. Write a function that prints We like Javascript! 1000 times. 2. Write a function printOdds(start, end) which prints all of the odd number starting with start up to and including end. 3. Write a function countByTens that counts to 10,000 by 10s (printing the sequence 10, 20, 30, .. 10,000). 4. Write a function named poly that uses a for loop to make a turtle draw any regular polygon (regular means all sides the same lengths, all angles the same, to find the angle, divide 360 by the number of sides). The function must have size and numSides as parameters. So, poly(40, 4) would draw a square where the sides are 40 pixels long. 5. Write a function countPrimes(a, b) which counts all of the prime numbers between a and b, including a and b. Your function must return the count. It should not print anything to the console. 6. Center text. The .length attributes of a string tells us how many characters are in the string, "cat".length === 3. Using this property and a for loop, write a function that centers text in the console. Your function must have two parameters – the text that needs to be centered, and the number of characters in the console. The function returns a new string, padded with enough blank spaces on the left side so that it will be centered. The function does not print to the console. 7. (hard bonus) Consider the isPrime example above. Our solution would be considered a naive solution – a solution which solve the problem in a basic, but not most efficient or elegant manner. Thinking (or reading) about prime numbers, can you refactor isPrime so that it can determine if a number is prime without having to complete all of the iterations between 2 and n? ## For Loop Lab For the for loop lab we’re going to return to our turtle graphics programming. We’ve already seen many interesting shapes and patterns that can be made with loops. For this lab, you are going to use turtle to draw a picture, with these simple guidelines: • all of your code is encapsulated in functions, except for the call to main() which starts your program • (at least) 3 different things in your picture are created by generalized functions. Generalized functions use function parameters to allow one function to handle different cases. In turtle, these parameters may control things like size, color, placement on the screen, etc. • you use for loops to place more than one “think” in your picture If you are unsure how to start, consider drawing a city. You can write functions for buildings, windows, using for loops to place the windows on a building and building inside your drawing. # While loops ## The while statement Here is a fragment of code that demonstrates the use of the while statement: /** * Return the sum of 1+2+3 ... n */ function sumTo(n) { let total = 0; let v = 1; while (v <= n) { total += v; v++; } return total; } console.log("sumTo(4) => 10", sumTo(4) === 10); console.log("sumTo(1000) =>500500 ", sumTo(1000) === 500500); You can almost read the while statement as if it were English. It means, while v is less than or equal to n, continue executing the body of the loop. Within the body, each time, increment v. When v passes n, return your accumulated sum. More formally, here is precise flow of execution for a while statement: • Evaluate the condition at line 4, yielding a value which is either false or true. • If the value is false, exit the while statement and continue execution at the next statement (line 8 in this case). • If the value is true, execute each of the statements in the body (lines 6 and 7) and then go back to the while statement at line 5. The body consists of all of the statements indented below the while keyword. Notice that if the loop condition is false the first time we test it, the statements in the body of the loop are never executed. The body of the loop should change the value of one or more variables so that eventually the condition becomes false and the loop terminates. Otherwise the loop will repeat forever, which is called an infinite loop. An endless source of amusement for computer scientists is the observation that the directions on shampoo, “lather, rinse, repeat”, are an infinite loop. In the case here, we can prove that the loop terminates because we know that the value of n is finite, and we can see that the value of v increments each time through the loop, so eventually it will have to exceed n. In other cases, it is not so easy, even impossible in some cases, to tell if the loop will ever terminate. What you will notice here is that the while loop is more work for you — the programmer — than the equivalent for loop. When using a while loop you have to manage the loop variable yourself: give it an initial value, test for completion, and then make sure you change something in the body so that the loop terminates. By comparison, here is an equivalent function that uses for instead: // Return the sum of 1+2+3 ... n function sumTo(n) { let ss = 0; for (let v = 1; v <= n; v++) { ss = ss + v; } return ss; } So why have two kinds of loop if for looks easier? This next example shows a case where we need the extra power that we get from the while loop. ## The Collatz 3n + 1 sequence Let’s look at a simple sequence that has fascinated and foxed mathematicians for many years. They still cannot answer even quite simple questions about this. The “computational rule” for creating the sequence is to start from some given n, and to generate the next term of the sequence from n, either by halving n, (whenever n is even), or else by multiplying it by three and adding 1. The sequence terminates when n reaches 1. This Javascript function captures that algorithm: // Print the 3n+1 sequence from n, // terminating when it reaches 1. function seq3np1 (n) { let sequence = ""; while (n !== 1) { sequence += n + ", "; if (n % 2 === 0) { // n is even n = Math.floor(n/2); } else { // n is odd n = n * 3 + 1; } } console.log(sequence + 1 + "."); } See Collatz repl First, note that we use the accumulator pattern that we introduced in the last chapter to concatenate our output to the (initially empty) string, sequence. Not until we complete the while loop do we print sequence to the console. The condition for continuing with this loop is n !== 1, so the loop will continue running until it reaches its termination condition, (i.e. n === 1). Each time through the loop, the program joins the value of n to sequence and then checks whether it is even or odd. If it is even, the value of n is divided by 2 (and then rounded down using Math.floor). If it is odd, the value is replaced by n * 3 + 1. Because of the logic for how the loop variable (n) changes in each iteration, this algorithm cannot be easily implemented with a for loop, because the for loop finalization statement cannot handle the boolean logic of deciding how to modify n. In this case, while is more suitable. Here are some examples: ⠕ seq3np1(3) 3, 10, 5, 16, 8, 4, 2, 1. ⠕ seq3np1(19) 19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. ⠕ seq3np1(21) 21, 64, 32, 16, 8, 4, 2, 1. ⠕ seq3np1(16) 16, 8, 4, 2, 1. Since n sometimes increases and sometimes decreases, there is no obvious proof that n will ever reach 1, or that the program terminates. For some particular values of n, we can prove termination. For example, if the starting value is a power of two, then the value of n will be even each time through the loop until it reaches 1. The previous example ends with such a sequence, starting with 16. See if you can find a small starting number that needs more than a hundred steps before it terminates. Particular values aside, the interesting question was first posed by a German mathematician called Lothar Collatz: the Collatz conjecture (also known as the 3n + 1 conjecture), is that this sequence terminates for all positive values of n. So far, no one has been able to prove it or disprove it! (A conjecture is a statement that might be true, but nobody knows for sure.) Think carefully about what would be needed for a proof or disproof of the conjecture “All positive integers will eventually converge to 1 using the Collatz rules”. With fast computers we have been able to test every integer up to very large values, and so far, they have all eventually ended up at 1. But who knows? Perhaps there is some as-yet untested number which does not reduce to 1. You’ll notice that if you don’t stop when you reach 1, the sequence gets into its own cyclic loop: 1, 4, 2, 1, 4, 2, 1, 4 … So one possibility is that there might be other cycles that we just haven’t found yet. Wikipedia has an informative article about the Collatz conjecture. The sequence also goes under other names (Hailstone sequence, Wonderous numbers, etc.), and you’ll find out just how many integers have already been tested by computer, and found to converge! ## Tracing a program To write effective computer programs, and to build a good conceptual model of program execution, a programmer needs to develop the ability to trace the execution of a computer program. Tracing involves becoming the computer and following the flow of execution through a sample program run, recording the state of all variables and any output the program generates after each instruction is executed. To understand this process, let’s trace the call to seq3np1(3) from the previous section. At the start of the trace, we have a variable, n (the parameter), with an initial value of 3. Since 3 is not equal to 1, the while loop body is executed. 3 is printed and 3 % 2 === 0 is evaluated. Since it evaluates to false, the else branch is executed and 3 * 3 + 1 is evaluated and assigned to n. To keep track of all this as you hand trace a program, make a column heading on a piece of paper for each variable created as the program runs and another one for output. Our trace so far would look something like this: n output printed so far -- --------------------- 3 3, 10 Since 10 !== 1 evaluates to true, the loop body is again executed, and 10 is printed. 10 % 2 === 0 is true, so the if branch is executed and n becomes 5. By the end of the trace we have: n output printed so far -- --------------------- 3 3, 10 3, 10, 5 3, 10, 5, 16 3, 10, 5, 16, 8 3, 10, 5, 16, 8, 4 3, 10, 5, 16, 8, 4, 2 3, 10, 5, 16, 8, 4, 2, 1 3, 10, 5, 16, 8, 4, 2, 1. Tracing can be a bit tedious and error prone (that’s why we get computers to do this stuff in the first place!), but it is an essential skill for a programmer to have. From this trace we can learn a lot about the way our code works. We can observe that as soon as n becomes a power of 2, for example, the program will require ${\log_2}(n)$ executions of the loop body to complete. We can also see that we don’t reach the final 1 within the body of the loop, which is why we concatenate 1 after our while loop terminates. In this function, we just store all of the values of the Collatz sequence in a single string. As we learn a bit more Javascript, we’ll be able to show you how to generate a list of values to hold the sequence, rather concatenating them to a string. ## Counting digits The following function counts the number of decimal digits in a positive integer: function numDigits(n) { let count = 0; while (n != 0) { count++; n = Math.floor(n / 10); } return count; } A call to console.log(numDigits(710)) will print 3. Trace the execution of this function call (using console.log or just a piece of paper) to convince yourself that it works. This function demonstrates an important pattern of computation called a counter. The variable count is initialized to 0 and then incremented each time the loop body is executed. When the loop exits, count contains the result — the total number of times the loop body was executed, which is the same as the number of digits. If we wanted to only count digits that are either 0 or 5, adding a conditional before incrementing the counter will do the trick: function numZeroAndNumFiveDigits(n) { let count = 0; while( n > 0) { let digit = n % 10; if (digit === 0 || digit === 5) { count = count + 1 } n = Math.floor(n / 10); } return count; } Confirm that numZeroAndNumFiveDigits(1055030250) === 7. Notice, however, that numDigits(0) === 0. Explain why. Do you think this is a bug in the code, or a bug in the specifications, or our expectations, or the tests? ## Newton’s method for finding square roots Loops are often used in programs that compute numerical results by starting with an approximate answer and iteratively improving it. For example, before we had calculators or computers, people needed to calculate square roots manually. Newton used a particularly good method (there is some evidence that this method was known many years before). Suppose that you want to know the square root of n. If you start with almost any approximation, you can compute a better approximation (closer to the actual answer) with the following formula: better = (approx + n/approx)/2 Repeat this calculation a few times using your calculator. Can you see why each iteration brings your estimate a little closer? One of the amazing properties of this particular algorithm is how quickly it converges to an accurate answer — a great advantage for doing it manually. By using a loop and repeating this formula until the better approximation gets close enough to the previous one, we can write a function for computing the square root. (In fact, this is how your calculator finds square roots — it may have a slightly different formula and method, but it is also based on repeatedly improving its guesses.) This is an example of an indefinite iteration problem: we cannot predict in advance how many times we’ll want to improve our guess — we just want to keep getting closer and closer. Our stopping condition for the loop will be when our old guess and our improved guess are “close enough” to each other. Ideally, we’d like the old and new guess to be exactly equal to each other when we stop. But exact equality is a tricky notion in computer arithmetic when real numbers are involved. Because real numbers are not represented absolutely accurately (after all, a number like pi or the square root of two has an infinite number of decimal places because it is irrational), we need to formulate the stopping test for the loop by asking “is a close enough to b”? This stopping condition can be coded like this: if (Math.abs(a-b) < 0.001) { // Make this smaller for better accuracy break } Notice that we take the absolute value of the difference between a and b. function sqrt(n) { let approx = n/2; // Start with some or other guess at the answer let better = (approx + n/approx)/2; while (Math.abs(approx - better) > .001) { approx = better; better = (approx + n/approx)/2.0; } return better; } // Test cases console.log(sqrt(25)); console.log(sqrt(49)); console.log(sqrt(81)); See Newton Square Root repl The output is: 5.000000000016778 7 9.000000000004924 See if you can improve the approximations by changing the stopping condition. Also, step through the algorithm (perhaps by hand, using your calculator or by adding a count variable to the loop) to see how many iterations were needed before it achieved this level of accuracy for sqrt(25). ## Algorithms Newton’s method is an example of an algorithm: it is a mechanical process for solving a category of problems (in this case, computing square roots). Some kinds of knowledge are not algorithmic. For example, learning dates from history or your multiplication tables involves memorization of specific solutions. But the techniques you learned for addition with carrying, subtraction with borrowing, and long division are all algorithms. Or if you are an avid Sudoku puzzle solver, you might have some specific set of steps that you always follow. One of the characteristics of algorithms is that they do not require any intelligence to carry out. They are mechanical processes in which each step follows from the last according to a simple set of rules. And they’re designed to solve a general class or category of problems, not just a single problem. Understanding that hard problems can be solved by step-by-step algorithmic processes (and having technology to execute these algorithms for us) is one of the major breakthroughs that has had enormous benefits. So while the execution of the algorithm may be boring and may require no intelligence, algorithmic or computational thinking — i.e. using algorithms and automation as the basis for approaching problems — is rapidly transforming our society. Some claim that this shift towards algorithmic thinking and processes is going to have even more impact on our society than the invention of the printing press. And the process of designing algorithms is interesting, intellectually challenging, and a central part of what we call programming. Some of the things that people do naturally, without difficulty or conscious thought, are the hardest to express algorithmically. Understanding natural language is a good example. We all do it, but so far no one has been able to explain how we do it, at least not in the form of a step-by-step mechanical algorithm. ## While Loop Exercises Some of these exercises work best with while loops, while others can be solved more easily with for loops. Some of them will work better if you write more than one function for the solution. The most straightforward applications of loops, given what we have learned so far, is working with numbers. Please review some basic terms and concepts that will help you with these exercises. A prime number is a whole number greater than 1 that can only be evenly divided by 1 and itself. Factors are number that multiply together produce a number. 2 and 3 are factors of 6 because $2 x 3=6$. Is the result of multiple multiplying a number. 18 is a multiple of 3 because $6 x 3 = 18$. The site Math is Fun offers a straightforward definition of multiples and factors with links to other pages relevant to these problems. You can get started by forking this repl with the function definitions 1. Sum range Write a function sumRange(start, end) that sums (adds up) all of the numbers between start and end, including start and end. Return the sum (a number). 2. Square Root Count Revise the code above for Newton’s method for calculating square roots. Instead of returning the square root, it should return the number of iterations required to find the square root. 3. Sum of odds sumOfOdds(start, end) calculates and returns the sum of all of the odd numbers in the range start..end. It includes start and end if they are odd numbers. 4. Sum of Squares Write a function that calculates and returns the sum of the squares of numbers in a range: sumOfSquare(start, end). The range includes start and end. 5. Greatest factor Write a function greatestFactor(start, end, n) that returns the greatest (highest) factor of n in the range of numbers between start and end (including end). 1. Greatest Common Factor Write a function gcm(a, b) that returns the greatest (highest number) that is a factor of both a and b. 2. Factorials Write a function fact(n) which returns the factorial of n (n!). The factorial of a number is that number multiplied by all of the numbers between itself and 1, so the factorial of 4 is $4 x 3 x 2 x 1 = 24$. In Javascript, we’d say fact(4) === 24. 3. Fibonacci Sequence Each term in the Fibonacci Sequence is calculated by adding the two previous numbers in the sequence together. The first two terms can by 0, and 1, so the next term is 1. The sequence begins 0, 1, 1, 2, 3, 5, 8, 13. Write a function fib(n) which returns the nth number in the sequence. So, fib(0) === 0, fib(3) === 5 and so on. 4. Armstrong Numbers An Armstrong Number is a number where the sum of the digits raised to the number of digits in the number, equal the number itself. 153 is an Armstrong Number. It has 3 digits, so $1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153$ Write a function isArmstrong(n) that returns true if n is an Armstrong Number, or false if it isn’t. # Strings ## A compound data type So far we have seen built-in types like number, string, and boolean. We’ve also started working with arrays, although we’ll take a closer look in the next chapter. Strings and arrays are qualitatively different from the others because they are made up of smaller pieces. In the case of strings, they’re made up of smaller strings each containing one character. Types that comprise smaller pieces are called compound data types. Depending on what we are doing, we may want to treat a compound data type as a single thing, or we may want to access its parts. This ambiguity is useful. ## Working with strings as single things Strings are objects. Objects can provide functions that work with the data of a string instance. For example: ⠕ let ss = "Hello, World!"; ⠕ let tt = ss.toUpperCase(); ⠕ tt => 'HELLO, WORLD!'  toUpperCase is a method that can be invoked on any string object to create a new string, in which all the characters are in uppercase. (The original string ss remains unchanged.) There are also methods such as toLowerCase, trim, and repeat that do other interesting things. To learn what methods are available and what they do, you can consult the MDN Documentation. Or, simply type the following into a Repl.it script: let ss = "Hello, World!"; let tt = ss. When you type the period to select one of the methods of ss, Repl.it will pop up a selection window showing all the methods that could be used on your string. There are lots of methods. In this chapter we’ll look at some of the most immediately useful ones. ## Working with the parts of a string The indexing operator (Javascript uses square brackets to enclose the index) selects a single character substring from a string: ⠕ let fruit = "banana"; ⠕ let m = fruit[1]; ⠕ console.log(m); The expression fruit[1] selects character number 1 from fruit, and creates a new string containing just this one character. The variable m refers to the result. When we display m, we could get a surprise: a Computer scientists always start counting from zero! The letter at subscript position zero of "banana" is b. So at position [1] we have the letter a. If we want to access the zero-eth letter of a string, we just place 0, or any expression that evaluates to 0, inbetween the brackets: ⠕ m = fruit[0]; ⠕ console.log(m); b The expression in brackets is called an index. An index specifies a member of an ordered collection, in this case the collection of characters in the string. The index indicates which one you want, hence the name. It can be any integer expression. We already mentioned that the common variable name i for loop variables can be thought of as shorthand for index. Consider this for loop which iterates through the characters in a string: let fruit = "banana"; for (let i = 0; i < fruit.length; i++) { console.log(i, fruit[i]); } produces: 0 'b' 1 'a' 2 'n' 3 'a' 4 'n' 5 'a' If you take a close look at the loop condition from our example, you’ll see that our for loop ends when i < fruit.length. length is a property of a string that lets us know how many characters are in the string. In later chapters we’ll see that arrays and other compound datatypes have a length property that makes it easy for us to iterate over the items they contain. Note that indexing string returns a string — Javascript has no special type for a single character. It is just a string of length 1. We’ve also seen arrays previously. The same indexing notation works to extract elements from an array: ⠕ let primeNumbers = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]; ⠕ primeNumbers[4]; => 11 ⠕ let friends = ["Joe", "Zoe", "Brad", "Angelina", "Zuki", "Thandi", "Paris"]; ⠕ friends[3]; 'Angelina' ## Length We’ve seen that the length property of a string, returns the number of characters in the string: ⠕ let fruit = "banana"; ⠕ fruit.length; 6 To get the last letter of a string, you might be tempted to try something like this: ⠕ let sz = fruit.length; ⠕ let last = fruit[sz]; ⠕ last; => undefined We see that last is undefined. The reason is that there is no character at index position 6 in "banana". Because we start counting at zero, the six indexes are numbered 0 to 5. To get the last character, we have to subtract 1 from the length of fruit: ⠕ let sz = fruit.length; ⠕ let last = fruit[sz - 1]; ⠕ last; => 'a' Here we see that the last character is fruit[fruit.length - 1], so the second to last character would be fruit[fruit.length - 2] and so on. ## Traversal and the for loop A lot of computations involve processing a string one character at a time. Often they start at the beginning, select each character in turn, do something to it, and continue until the end. This pattern of processing is called a traversal. One way to encode a traversal is with a while statement: let ix = 0; while (ix < fruit.length) { let letter = fruit[ix]; console.log(letter); ix++; } The loop condition is ix < fruit.length, so when ix is equal to the length of the string, the condition is false, and the body of the loop is not executed. The last character accessed is the one with the index fruit.length - 1, which is the last character in the string. But we’ve previously seen how the for loop can easily iterate over the elements in a list and it can do so for strings as well: for (let i = 0; i < fruit.length; i++) { console.log(fruit[i]); } As we iterate through the characters in fruit, the loop variable, i represents each index in the string. The loop continues until no characters are left. Here we can see the expressive power the for loop gives us compared to the while loop when traversing a string. The following example shows how to use concatenation and a for loop to generate an abecedarian series. Abecedarian refers to a series or list in which the elements appear in alphabetical order. For example, in Robert McCloskey’s book Make Way for Ducklings, the names of the ducklings are Jack, Kack, Lack, Mack, Nack, Ouack, Pack, and Quack. This loop outputs these names in order: let prefixes = "JKLMNOPQ"; let suffix = "ack"; for (let i = 0; i < prefixes.length; i++) { console.log(prefixes[i] + suffix); } Jack Kack Lack Mack Nack Oack Pack Qack Of course, that’s not quite right because Ouack and Quack are misspelled. You’ll fix this as an exercise below. ## Substrings A substring of a string is obtained by taking a smaller sequence of characters from an existing string to create a new string. ⠕ let s = "Pirates of the Caribbean"; ⠕ console.log(s.substring(0,7)); Pirates ⠕ console.log(s.substring(11:14)); the ⠕ console.log(s.substring(15:24)); Caribbean The substring(startIndex, endIndex) method of a string, returns a new string without modifying the original string. The new string (i.e. the substring) starts at (and includes) the character at startIndex and ends at (but excludes) the character at endIndex. This behavior makes sense if you imagine the indices pointing between the characters, as in the following diagram: If you imagine this as a piece of paper, substring(m, n) copies out the part of the paper between the n and m positions. Provided m and n are both within the bounds of the string, your result will be of length (m-n). There are a few more tricks to substring. If you omit the second argument (endIndex), the function returns a substring from startIndex up to and including the last character in the string. If you provide an endIndex greater than string.length, From the MDN documentation, we learn the following additional rules and behaviors for substring. • If the indexEnd argument is omitted, substring() returns the substring from startIndex to the end of the string • If indexStart is equal to indexEnd, substring() returns an empty string • If indexStart is greater than indexEnd, the substring() swaps the two arguments • Any argument value that is less than 0 is treated as 0 • Any argument than string.length is treated as if it were string.length • Any argument value that is NaN is treated as if it were 0 ## String comparison The Boolean comparison operators work on strings. To see if two strings are equal: if (word === "banana") { console.log("Yes, we are bananas!"); } Other comparison operations are useful for putting words in lexicographical order: if (word < "banana") { console.log("Your word, " + word + ", comes before banana."); } else if (word > "banana") { console.log("Your word, " + word + ", comes after banana."); } else { console.log("Yes, we have no bananas!"); } Keep in mind that Javascript string comparisons are case sensitive, so, for exampe “Ape” does not equal “ape”. A common way to address the problem of case is to convert strings to a standard format, such as all lowercase, before performing the comparison. So: ⠕ let a = "Ape"; ⠕ let b = "ape"; ⠕ a === b; => false ⠕ a = a.toLowerCase(); ⠕ a === b; => true ## Strings are immutable It is tempting to use the [] operator on the left side of an assignment, with the intention of changing a character in a string. For example: let greeting = "Hello, world!"; greeting[0] = 'J'; console.log(greeting); At best, the assignment on line 2 above will have no effect. If you run the code in strict mode, you will get an error. Strings are immutable, which means you can’t change an existing string. The best you can do is create a new string that is a variation on the original: let greeting = "Hello, world!"; let newGreeting = "J" + greeting.substring(1); console.log(newGreeting); The solution here is to concatenate a new first letter onto a slice of greeting. This operation has no effect on the original string. ## Testing inclusion Javascript provides string functions that let us find substrings within a string. includes returns a Boolean true or false to indicate if the substring exists in the string. ⠕ let s = "apple"; ⠕ s.includes("p"); => true ⠕ s.includes("i"); => false ⠕ s.includes("app"); => true ⠕ s.includes("App"); // false because case doesn't match => false Note that a string is a substring of itself, and the empty string is a substring of any other string. (Also note that computer scientists like to think about these edge cases quite carefully!) ⠕ s.includes("apple"); => true ⠕ s.includes(""); => true Combining includes with string concatenation using +=, we can remove the vowels from a string: function removeVowels(s) { let vowels = "aeiou"; let sansVowels = ""; for (let i = 0; i < s.length; i++) { let c = s[i].toLowerCase(); if(!vowels.includes(c)) { sansVowels += s[i]; } } return sansVowels; } console.log(removeVowels("CompSci")); // CmpSc console.log(removeVowels("A dark and stormy night.")); // drk nd strmy nght. Check out this function on repl.it This short function uses several of the techniques and patterns we have previously seen. We use a finite for loop to iterate up to s.length to traverse the string. We convert c to lowercase for the comparison where we test for inclusion in vowels. We create an empty string, sansVowels that accumulates the non-vowel characters that we find. ## A find function What does the following function do? // Find and return the index of ch in strng. // Return -1 if ch does not occur in strng. function find(strng, ch) { for(let i = 0; i < strng.length; i++) { if(strng[i] === ch) { return i; } } return -1; } test(find("Compsci", "p") == 3) test(find("Compsci", "C") == 0) test(find("Compsci", "i") == 6) test(find("Compsci", "x") == -1) In a sense, find is the opposite of the indexing operator. Instead of taking an index and extracting the corresponding character, it takes a character and finds the index where that character appears. If the character is not found, the function returns -1. This is another example where we see a return statement inside a loop. If strng[i] === ch, the function returns immediately, breaking out of the loop prematurely. If the character doesn’t appear in the string, then the program exits the loop normally and returns -1. This pattern of computation is sometimes called a eureka traversal or short-circuit evaluation, because as soon as we find what we are looking for, we can cry “Eureka!”, take the short-circuit, and stop looking. ## Looping and counting The following program counts the number of times the letter a appears in a string, and is another example of the counter pattern. function countA(text) { let count = 0; for (let i = 0; i < text.length; i++) { if (text[i] === "a") { count++; } } return count; } console.log(countA("banana") === 3); ## Default parameters To find the locations of the second or third occurrence of a character in a string, we can modify the find function, adding a third parameter for the starting position in the search string: function find2(strng, ch, start) { let ix = start; while (ix < strng.length) { if (strng[ix] == ch) { return ix; } ix++; } return -1 } console.log(find2("banana", "a", 2) == 3); The call find2("banana", "a", 2) now returns 3, the index of the first occurrence of “a” in “banana” starting the search at index 2. What does find2("banana", "n", 3) return? If you said, 4, there is a good chance you understand how find2 works. Better still, we can combine find and find2 using a default parameter: function find(strng, ch, start = 0) { let ix = start; while (ix < strng.length) { if (strng[ix] == ch) { return ix; } ix++; } return -1 } When a function has an optional default parameter, the caller may provide a matching argument. If the third argument is provided to find, it gets assigned to start. But if the caller leaves the argument out, then start is given a default value indicated by the assignment start = 0 in the function header. So the call find("banana", "a", 2) to this version of find behaves just like find2, while in the call find("banana", "a"), start will be set to the default value of 0. Adding another optional parameter to find makes it search from a starting position, up to but not including the end position: function find(strng, ch, start = 0, end = null) { let ix = start; end = end || strng.length; while (ix < end) { if (strng[ix] == ch) { return ix; } ix++; } return -1 }  The optional value for end is interesting: we give it a default value null if the caller does not supply any argument. In the body of the function we test what end is, and if the caller did not supply any argument, we reassign end to be the length of the string. If the caller has supplied an argument for end, however, the caller’s value will be used in the loop. On line 3 we see a new use of the logical || operator in the assignment expression, end = end || strng.length;. We re-assign end the value of end (i.e. it doesn’t change) if end is truthy value, or we assign end a default value, of strng.length. Because of the way Javascripts logical operators and truthiness work, they can be useful for assignment. As you read more Javascript code online and in books, you will see many examples of code that use the || operator to assign default values. Here are some test cases that should print true: let ss = "Javascript strings have some interesting methods."; console.log(find(ss, "s") === 4); console.log(find(ss, "s", 11) === 11); console.log(find(ss, "s", 12) === 17); console.log(find(ss, "s", 12, 17) === -1); console.log(find(ss, ".") === ss.length - 1); ## The built-in indexOf method We wrote our own find function above, but Javascript’s string object includes its own version of find called indexOf. let ss = "Javascript strings have some interesting methods."; console.log(ss.indexOf("s") === 4); console.log(ss.indexOf("s", 11) === 11); console.log(ss.indexOf("s", 12) === 17); console.log(ss.indexOf("s", 12, 17) === 17); // indexOf ignores the argument to end console.log(ss.indexOf(".") === ss.length - 1); indexOf does not have the optional end paremeter. It always seachers until the end of the string. In the case ss.indexOf("s", 12, 17) === 17 it does not create an error to pass in the third argument, however it is ignored entirely. The built-in indexOf method is more general than our version. It can find substrings, not just single characters: ⠕ "banana".indexOf("nan") => 2 ⠕ "banana".indexOf("na", 3) => 4 Usually we’d prefer to use the methods that Javascript provides rather than reinvent our own equivalents. But many of the built-in functions and methods make good teaching exercises, and the underlying techniques you learn are your building blocks to becoming a proficient programmer. ## The split method One of the most useful methods on strings is the split method: it splits a single multi-word string into an array of individual words (“substrings”). The first parameter of split specifies the character or substring (or regular expression, we’ll see later) to be used to break the string into words. In the example below, we split ss into words using a single space ' '; ⠕ let ss = "Well I never did said Alice"; ⠕ let words = ss.split(" "); ⠕ words => ['Well', 'I', 'never', 'did', 'said', 'Alice'] ## Cleaning up your strings We’ll often work with strings that contain punctuation, or tab and newline characters, especially, as we’ll see in a future chapter, when we read our text from files or from the Internet. But if we’re writing a program, say, to count word frequencies or check the spelling of each word, we’d prefer to strip off these unwanted characters. We’ll show just one example of how to strip punctuation from a string. Remember that strings are immutable, so we cannot change the string with the punctuation — we need to traverse the original string and create a new string, omitting any punctuation: function removePunctuation(s) { let punctuation = "!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~";
let cleanString = "";
for (let i = 0; i < s.length; i++) {
if (punctuation.indexOf(s[i]) === -1) {
cleanString += s[i];
}
}
return cleanString;
}

Composing together this function and the split method from the previous section makes a useful combination — we’ll clean out the punctuation, and split will clean out the newlines and tabs while turning the string into a list of words:

let text = Born two centuries ago, Ada Lovelace was a pioneer of computer
science. She took part in writing the first published program and was a
computing visionary, recognizing for the first time that computers could do
much more than just calculations!;

let words = removePunctuation(text).toLowerCase().split(/\s/);
console.log(words);

The output:

[ 'born',
'two',
'centuries',
'ago',
'lovelace',
...
'much',
'more',
'than',
'just',
'calculations' ]                   

Careful readers will have noticed a new syntax for the argument to split, above. /\s/ is a Javascript regular expression (aka regex) which splits the string on any whitespace — regular spaces, tabs, and newlines. Regular expressions are powerful patterns for matching (and replacing) substrings in strings. Many of the Javascript string methods accept either plain strings are regular expressions as arguments. Regular expressions are beyond the scope of this chapter, but we will demonstrate a few useful examples. MDN offers a guide to using Regular Expressions in Javascript.

There are other useful string methods, but this book isn’t intended to be a reference manual. On the other hand, the Mozilla Developers Network is an excellent reference. You can see all of the String methods here <https://developer.mozilla.org/en- US/docs/Web/JavaScript/Reference/Global_Objects/String>.

## Template strings

Template strings are the easiest and most powerful way to format strings in Javascript. We have already seen how we can use them with the backtick () for multiline strings.

Template strings allow us to embed Javascript expressions in a string without using string concatenation. Here are some examples:

let s1 = The Javascript value of π from the math library is ${Math.PI}; console.log(s1); let name = "Alice"; let age = 10; let s2 = I am${name} and I am ${age} years old.; console.log(s2); let n1 = 4; let n2 = 5; s3 = 2**10 =${2**10} and ${n1} *${n2} = ${n1 * n2}; console.log(s3); The Javascript value of π from the math library is 3.141592653589793 I am Alice and I am 10 years old. 2**10 = 1024 and 4 * 5 = 20 The template strings resolve any Javascript expression inside the ${} placeholders to a string and then concatenate the template string into a single string. They can make our code both easier to read and easier to write. You can learn more about template strings from the docs.

## Glossary

compound data type

A data type in which the values are made up of components, or elements, that are themselves values.

default value

The value given to an optional parameter if no argument for it is provided in the function call.

dot notation

Use of the dot operator, ., to access methods and properties of an object.

immutable data value

A data value which cannot be modified. Assignments to elements or slices (sub-parts) of immutable values cause a runtime error.

index

A variable or value used to select a member of an ordered collection, such as a character from a string, or an element from a list.

indexing ([])

Access a single character in a string using its position (starting from 0). Example: "This"[2] evaluates to "i".

length property (string.length)

Returns the number of characters in a string. Example: "happy".length evaluates to 5.

mutable data value

A data value which can be modified. The types of all mutable values are compound types. Lists and dictionaries are mutable; strings and tuples are not.

optional parameter

A parameter written in a function header with an assignment to a default value which it will receive if no corresponding argument is given for it in the function call.

regular expression

A pattern expressed using the regular expression language to find a substring within string.

short-circuit evaluation

A style of programming that shortcuts extra work as soon as the outcome is know with certainty. In this chapter our find function returned as soon as it found what it was looking for; it didn’t traverse all the rest of the items in the string.

substring

A part of a string (substring) specified by a range of indices. More generally, a subsequence of any sequence type in Javascript can be created using the substring method of string: "testing".substring(0,4).

traverse

To iterate through the elements of a collection, performing a similar operation on each.

whitespace

Any of the characters that move the cursor without printing visible characters. Whitespace in Javascript can be represented by the regular expression /\s/.

## String Exercises

1. Count vowels. Write a function countVowels(str) that returns the number of vowels in the string str.

2. Quack. Modify:

let prefixes = "JKLMNOPQ";
let suffix = "ack";

for (let i = 0; i < prefixes.length; i++) {
console.log(prefixes[i] + suffix);
}

so that Ouack and Quack are spelled correctly.

3. Count substring Write a function that counts how many times a substring occurs in a string. Example: count("an", "banana") === 2.

4. Remove letter. Write a function that removes all occurrences of a given letter from a string: removeLetter("cat", "a") === "ct".

5. Reverse. Write a function reverse(text) that returns text with the letters reversed. So, reverse("happy") === "yppah"

6. Palindrome. Write a function isPalindrome(text) that returns true if text is a palindrome, or false if it is not. A string is a palindrome if it reads the same forwards and backwards. (Hint: use your reverse function to make this easy!)

# Array

A array is an ordered collection of values. The values that make up an array are called its elements, or its items.

We will use the term element or item to mean the same thing. Arrays are similar to strings, which are ordered collections of characters, except that the elements of an array can be of any type. Arrays and strings — and other collections that maintain the order of their items — are called sequences or lists.

## Array values

There are several ways to create a new array; the simplest is to enclose the elements in square brackets ([ and ]):

let ps = [10, 20, 30, 40];
let qs = ["spam", "bungee", "swallow"];
let empty = [];

The first array contains four numbers. The second contains an array of three strings. The third is an empty array — it’s waiting for us to add elements. The elements of an array don’t have to be the same type. The following array contains a string, a number, and (amazingly) another array:

let zs = ["hello", 5, [10, 20]];

An array within another array is said to be nested.

We have already seen that we can assign array values to variables or pass arrays as parameters to functions:

⠕ let vocabulary = ["apple", "cheese", "dog"];
⠕ let numbers = [17, 123];
⠕ let anEmptyList = [];
⠕ console.log(vocabulary, numbers, an_empty_list)
[ 'apple', 'cheese', 'dog' ] [ 17, 123 ] []

## Accessing elements

The syntax for accessing the elements of an array is the same as the syntax for accessing the characters of a string — the index operator: [] (not to be confused with an empty array). The expression inside the brackets specifies the index. Remember that the indices start at 0 and can be integers up to length - 1:

⠕ numbers[0];
=> 17

Any expression evaluating to an integer can be used as an index:

⠕ numbers[9-8];
=> 123
⠕ numbers["1"]
=> undefined

If you try to access an element that does not exist, Javascript returns undefined:

⠕ numbers[5];
=> undefined

If you assign a value to an element that does not exist, Javascript will add the value to the array at that index, and create empty elements in the intervening indices.

⠕ numbers[5] = 22;
=> 22
⠕ numbers;
=> [ 17, 123, <3 empty items>, 22 ]
⠕ numbers[5];
=> 22

It is common to use a loop variable as a list index.

let horsemen = ["war", "famine", "pestilence", "death"];

for (let i = 0; i < horsemen.length; i++) {
console.log(horsemen[i]);
}

Each time through the loop, the variable i is used as an index into the array, printing the i’th element. This pattern of computation is called a array traversal.

Like strings, Javascript arrays have a length property that tells us how many items are in the array. When we use i < horsemen.length as the loop condition, our for loop stops when it accesses the last element of the array.

## Array membership

Javascript arrays have an includes method which returns a Boolean true or false to indicate membership of an item in an array.

⠕ let horsemen = ["war", "famine", "pestilence", "death"];
⠕ horsemen.includes("pestilence");
=> true
⠕ horsemen.includes("debauchery");
=> false
⠕ !horsemen.includes("debauchery");
true

## Array methods

The array concat method combines two arrays into a new array by concatenating an array to the end of another array:

⠕ let a = [1, 2, 3];
⠕ let b = [4, 5, 6];
⠕ let c = a.concat(b);
⠕ c
=> [ 1, 2, 3, 4, 5, 6 ]

Notice that a and b remain unchanged;

⠕ a
=> [ 1, 2, 3 ]
⠕ b
=> [ 4, 5, 6 ]

push adds elements to the end of an array and returns the new length of the array. You can pass more than one argument to push and it will create a new element at the end of the array for each parameter.

⠕ a
=> [ 1, 2, 3 ]
⠕ a.push(4);
=> 4
⠕ a
[ 1, 2, 3, 4 ]
⠕ a.push(3, 2, 1);
=> 7
⠕ a
[ 1, 2, 3, 4, 3, 2, 1 ]

pop() returns the last element in the array and removes that element from the array. When pop is called on an empty array, undefined is returned.

⠕ a = [ 1, 2, 3, 4 ];
⠕ a.pop();
=> 4
⠕ a
[ 1, 2, 3]

shift and unshift are equivalent to pop and push except they work on the beginning of an array. a.unshift(-1, 0) puts -1 in the 0’th element and 0 in the 1’th element. shift returns the 0’th element of the array and removes it from the array. All other elements are shifted to the left. like pop, shift returns undefined when called on an empty array.

There are many other useful array methods that you can read about in the documentation.

## Array slices

The slice() method of an array returns a new sub-array. slice is similar to the substring() method of strings.

⠕ let t = ["a", "b", "c", "d", "e", "f"];
⠕ t.slice(1, 3);
=> [ 'b', 'c' ]
⠕ t.slice(3);
=> [ 'd', 'e', 'f' ]
⠕ t.slice();
[ 'a', 'b', 'c', 'd', 'e', 'f' ]

The begin and end arguments are optional. If only begin is supplied, as in t.slice(3);, slice returns all elements from begin to the end of the array. If no arguments are provided (t.slice()) a copy of the entire array is returned.

## Arrays are mutable

Unlike strings, arrays are mutable, which means we can change their elements. Using the index operator on the left side of an assignment, we can update one of the elements:

⠕ let fruit = ["banana", "apple", "quince"];
⠕ fruit[0] = "pear";
⠕ fruit[2] = "orange";
⠕ fruit
[ 'pear', 'apple', 'orange' ]

The bracket operator applied to an array can appear anywhere in an expression. When it appears on the left side of an assignment, it changes one of the elements in the array, so the first element of fruit has been changed from "banana" to "pear", and the last from "quince" to "orange". An assignment to an element of an array is called item assignment. Item assignment does not work for strings:

⠕ let myString = "TEST";
⠕ myString[2] = "X";
=> 'X'
⠕ myString
=> 'TEST'

Javascript just ignores the illegal assignment and we see that myString remains unchanged. This is not the case for arrays:

⠕ let myCharArray = ["T", "E", "S", "T"];
⠕ myCharArray[2] = "X";
⠕ myCharArray
=> [ 'T', 'E', 'X', 'T' ]

With the splice method (not to be confused with slice), we can update, insert, or delete multiple array elements with a single function call.

shift and pop remove single items from the beginning or end of an array. splice is a more flexible (and complicated) method that can return and delete items from any array index, as well as insert or replace multiple items. splice can operate on more than one element. Here are a few ways to use splice. The syntax for splice is splice(index, numDelete, newItems...) where index indicates where the deletion or insertion should begin, numDelete (optionally) indicates how many items to remove. The remaining newItems can be any number of arguments to be inserted in the array at index.

Delete multiple items from an index:

⠕ let chars = ["a", "b", "c", "d", "e", "f"];
⠕ let removedChars = chars.splice(1, 2);
⠕ removedChars
=> [ 'b', 'c' ]
⠕ chars
=> [ 'a', 'd', 'e', 'f' ]

Because the numDelete argument is zero, this inserts items in the middle of an array:

⠕ let numbers = [10, 20, 30, 40];
⠕ numbers.splice(2, 0, 21, 22);
⠕ numbers
=> [ 10, 20, 21, 22, 30, 40 ]

By passing in the number of items to delete, we can replace multiple array elements with splice:

⠕ numbers = [10, 20, 30, 40];
⠕ numbers.splice(1, 2, 9, 8);
⠕ numbers
=> [ 10, 9, 8, 40 ]

## Objects and references

After we execute these assignment statements

let a = "banana";
let b = "banana";

we know that a and b will refer to a string object with the letters "banana". But we don’t know yet whether they point to the same string object.

There are two possible ways the Javascript interpreter could arrange its memory:

In one case, a and b refer to two different objects that have the same value. In the second case, they refer to the same object.

When we use the equality operator on strings, tells us if they hold the same value:

⠕ a === b
=> true

We cannot tell if they refere to the same object or not. Since strings are immutable, Javascript can optimize resources by making two names that refer to the same string value refer to the same object.

This is not the case with arrays:

⠕ let a = [1, 2, 3];
⠕ let b = [1, 2, 3];
⠕ a === b
=> false

The state snapshot here looks like this:

a and b have the same value but do not refer to the same object.

## Aliasing

Since variables refer to objects, if we assign one variable to another, both variables refer to the same object:

⠕ let a = [1, 2, 3];
⠕ let b = a;
⠕ a === b
=> true

In this case, the state snapshot looks like this:

Because the same array has two different names, a and b, we say that it is aliased. Changes made with one alias affect the other:

⠕ b[0] = 5
⠕ a
=> [ 5, 2, 3 ]

Although this behavior can be useful, it is sometimes unexpected or undesirable. In general, it is safer to avoid aliasing when you are working with mutable objects (i.e. arrays at this point in our textbook, but we’ll meet more mutable objects as we cover classes and objects). Of course, for immutable objects (i.e. strings), there’s no problem — it is just not possible to change something and get a surprise when you access an alias name. That’s why Javascript is free to alias strings (and any other immutable kinds of data) when it sees an opportunity to economize.

## Cloning arrays

If we want to modify an array and also keep a copy of the original, we need to be able to make a copy of the array itself, not just the reference. This process is sometimes called cloning, to avoid the ambiguity of the word copy.

The easiest way to clone an array is to call the slice method with zero arguments:

⠕ let a = [1, 2, 3];
⠕ let b = a.slice();
⠕ b
=> [ 1, 2, 3 ]
⠕ a === b
=> false

Calling slice always creates a new array. In this case the slice happens to consist of the whole array. So now the relationship is like this:

Now we are free to make changes to b without worrying that we’ll inadvertently be changing a:

⠕ b[0] = 5
⠕ a
[ 1, 2, 3 ]

## Array parameters

Passing an array as an argument actually passes a reference to the array, not a copy or clone of the array. So parameter passing creates an alias for you: the caller has one variable referencing the array, and the called function has an alias, but there is only one underlying array object.

For example, the function below takes an array as an argument and multiplies each element in the array by 2:

/**
* Overwrite each element in t with double its value
*/
function doubleStuff (t) {
for (let i = 0; i < t.length; i++) {
t[i] = t[i] * 2;
}
}

If we add the following onto our script:

let things = [2, 5, 9];
doubleStuff(things);
console.log(things);

When we run it we’ll get:

[ 4, 10, 18 ]

In the function above, the parameter t and the variable things are aliases for the same object. So changes to t or things are reflected in both t and things.

## Pure functions and modifiers

Functions which take arrays as arguments and change them during execution are called modifiers and the changes they make are called side effects.

A pure function does not produce side effects. It communicates with the calling program only through parameters, which it does not modify, and a return value. Here is doubleStuff written as a pure function:

/**
* Double the value of each element in array t
* and return a new array with the doubled values
*/
function doubleStuff (t) {
let tt = [];
for (let i = 0; i < t.length; i++) {
tt[i] = t[i] * 2;
}
return tt;
}

This version of doubleStuff does not change its arguments:

⠕ let things = [2, 5, 9];
⠕ let xs = doubleStuff(things);
⠕ things
=> [ 2, 5, 9 ]
⠕ xs
=> [ 4, 10, 18 ]

An early rule we saw for assignment said “first evaluate the right hand side, then assign the resulting value to the variable”. So it is quite safe to assign the function result to the same variable that was passed to the function:

⠕ let things = [2, 5, 9];
⠕ things = doubleStuff(things);
⠕ things
=> [ 4, 10, 18 ]

## Functions that produce arrays

The pure version of doubleStuff above made use of an important pattern for your toolbox. Whenever you need to write a function that creates and returns an array, the pattern is usually:

initialize a result variable to be an empty array
loop
create a new element
append it to result
return the result

Let us show another use of this pattern. Assume you already have a function isPrime(x) that can test if x is prime. Write a function to return an array of all prime numbers less than n:

/**
* Return an array of all prime numbers less than n.
*/
function primesLessThanN(n) {
let result = [];
for (let i = 2; i < n; i++) {
if (isPrime(i)) {
result.push(i);
}
}
return result;
}

## Strings and arrays

Two of the most useful methods on strings involve conversion to and from arrays of substrings.
The split method (which we’ve already seen) breaks a string into an array of words. We have been using the simple regular expression /\s/ to split strings at the whitespace pattern.

⠕ let song = "The rain in Spain...";
⠕ let words = song.split(/\s/);
⠕ words
=> [ 'The', 'rain', 'in', 'Spain...' ]

In this example the whitespace regex is the delimiter — the toke used to specify which string to use as the boundary marker between substrings. The following example uses the string ai as the delimiter:

⠕ song.split("ai");
=> [ 'The r', 'n in Sp', 'n...' ]

Notice that the delimiter doesn’t appear in the result.

The inverse of the split method is join. You choose a desired separator string, (often called the glue) and join the array with the glue between each of the elements:

⠕ let glue = ";";
⠕ let s = words.join(glue);
⠕ s
=> 'The;rain;in;Spain...'

The array that you glue together (words in this example) is not modified. Also, as these next examples show, you can use empty glue or multi-character strings as glue:

⠕ words.join(" --- ");
=> 'The --- rain --- in --- Spain...'
⠕ words.join("");
=> 'TheraininSpain...'

## Counting words

Using thesplit method of strings, we can write an elegant solution to counting words in a text by looping through the array of words. In the code below we look at section [Martin Luther King Jr’s 1963 “I have a dream …” speech] (https://www.archives.gov/files/press/exhibits/dream-speech.pdf) in order to count the number of times the word dream occurs.

let text = I say to you today, my friends, so even
though we face the difficulties of today and tomorrow,
I still have a dream. It is a dream deeply rooted in
the American dream. I have a dream that one day this
nation will rise up and live out the true meaning of
its creed: “We hold these truths to be self-evident:
that all men are created equal.” I have a dream that
one day on the red hills of Georgia the sons of former
and the sons of former slave owners will be able to
sit down together at the table of brotherhood.;

let words = text.split(/\s/);

let counter = 0;
for (let i = 0; i < words.length; i++) {
if (words[i].includes("dream")) {
counter++;
}
}

console.log(The speech has ${words.length} words. We found "dream"${counter} times.);

code walk through

Play with the code live at https://repl.it/@mcuringa/DreamWordCount

## Nested arrays

A nested array is an array that appears as an element in another array. In this array, the element with index 3 is a nested array:

⠕ let nested = ["hello", 2.0, 5, [10, 20]];

If we output the element at index 3, we get:

⠕ console.log(nested[3]);
=> [10, 20]

To extract an element from the nested array, we can proceed in two steps:

⠕ elem = nested[3];
⠕ elem[0]
=> 10

Or we can combine them:

⠕ nested[3][1]
=> 20

Bracket operators evaluate from left to right, so this expression gets the 3’th element of nested and extracts the 1’th element from it.

## Matrices

Nested arrays are often used to represent matrices. For example, the matrix:

might be represented as:

⠕ let mx = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];

mx is an array with three elements, where each element is a row of the matrix. We can select an entire row from the matrix in the usual way:

⠕ mx[1]
=> [4, 5, 6]

Or we can extract a single element from the matrix using the double-index form:

⠕ mx[1][2]
=> 6

The first index selects the row, and the second index selects the column. Although this way of representing matrices is common, it is not the only possibility.

## Glossary

aliases
Multiple variables that contain references to the same object.
array
A collection of values, each in a fixed position within the array.
clone
To create a new object that has the same value as an existing object. Copying a reference to an object creates an alias but doesn’t clone the object.
delimiter
A character or string (sometimes called a token) used to indicate where a string should be split.
element
One of the values in an array (or other sequence). The bracket operator selects elements of an array. Also called item.
immutable data value
A data value which cannot be modified.
index
An integer value that indicates the position of an item in an array. Indexes start from 0.
item
See element.
array traversal
The sequential accessing of each element in an array.
modifier
A function which changes its arguments inside the function body. Only mutable types can be changed by modifiers.
mutable data value
A data value which can be modified. The types of all mutable values are compound types. Arrays are mutable; strings are not.
nested array
An array which is an element of another array.
object
A thing to which a variable can refer.
pattern
A sequence of statements, or a style of coding something that has general applicability in a number of different situations. Part of becoming a mature Computer Scientist is to learn and establish the patterns and algorithms that form your toolkit. Patterns often correspond to your “mental chunking”.
pure function
A function which has no side effects. Pure functions only make changes to the calling program through their return values.
sequence
Any of the data types that consist of an ordered collection of elements, with each element identified by an index.
side effect
A change in the state of a program made by calling a function. Side effects can only be produced by modifiers.
step size
The interval between successive elements of a linear sequence. The third (and optional argument) to the range function is called the step size. If not specified, it defaults to 1.

## Array Examples

### Example 1: oddCount

Write a function to count how many odd numbers are in an array.

### Example 2: sumEvens

Sum up all the even numbers in an array.

### Example 3: findNegatives

Return an array with all of the negative numbers in an array. Do not modify the original array (i.e. write a pure function).

### Example 4: sumUpToEven

Sum all the elements in an array up to but not including the first even number. (What if there is no even number?)

### Example 5: olympicScores

Write a function that takes an array of numbers and returns the an array of numbers with the highest and lowest scores removed. Do not modify the original array parameter.

Check out the live code here: https://repl.it/@mcuringa/Array-Examples

## Array Exercises

1. Write a function called filterWord which takes an array of strings and a word to filter as arguments and returns a new array with all instances of word removed. This function should not modify the original array.
2. Count how many words in an array have length 5 (i.e. are 5 characters long).
3. Write a function that finds and returns the average of an array of numbers.
4. Write a function called removeDuplicates that takes an array and returns a new array with only the unique elements from the original. Hint: they don’t have to be in the same order. Hint hint: remember the includes method of array.
5. Write a function called combine that takes 2 arrays of strings as parameters and returns a new array of strings which concatenates the items from the first array with the item from the second. If the array are not equal in length, the new array will end with the item from the longer array. For example:

⠕ let a = ["cat", "dog", "bird"];
⠕ let b = ["lion", "wolf", "eagle"];
⠕ let c = combine(a, b);
⠕ console.log(c);
["catlion", "dogwolf", "birdeagle"]
6. Write a function called isSorted which takes an array (of number) as a parameter. It should return true if the array is already sorted (ascending order) or false if the array is not sorted.

You can use this function to test your code:

function test_isSorted() {

let n1 = [4, 77, 2, 4567, 12];
console.assert(!isSorted(n1), "n1 is not sorted, isSorted(n1) failed");
let n2 = [1, 2, 3, 4, 5];
console.assert(isSorted(n2), "n2 is not sorted, isSorted(n2) failed");
}
test_isSorted();

## Array Lab

Sentiment Analysis is a technique in computer science text analysis which tries to determine the sentiment or mood expressed in a text. Some “sentiments” are easy to detect. Given the text “I love dogs so much!”, we can confidently say it is positive. “I hate you and never want to talk to you again” is clearly negative. “The car is silver.” would express a neutral sentiment.

Unfortunately, language is often much trickier to classify. Consider, “I have too much homework” (negative) and “I don’t have too much homework” (positive).

For this lab, you are going to write the best sentiment function that you can. It won’t handle all cases, but try to handle as many as you can think of. You should use the string and array functions that we have been working with in the last two chapters.

Your function has a single string parameter, and returns 1 for a positive sentiment, -1 for a negative sentiment, and 0 for a neutral sentiments.

Use this repl to get started: https://repl.it/@mcuringa/Sentiment

You can read the Wikipedia article on sentiment analysis to get a better sense of this lab.

## Code Listing 2: School Test Data Report

### New York City Schools Data

The New York City public school system, run by the NYC Department of Education (DOE). Is the largest public school system in the United States, with over 1 million students in more than 2,000 schools. The schools are tasked with educating a diverse population, with almost 75% of students coming from economically disadvantaged families.

It is home to some of the best schools in the country, with selective schools like Stuyvesant High School and Bronx Science, but also faces chronically low performance in many of its schools. The schools face criticism and controversy surrounding a variety of issues. Black and Latinx students face the highest levels of segregation in the country; contributing to significant inequity within schools in New York City and with other New York State public schools in the wealthy suburbs that ring the city.

Some of the initiatives meant to address these challenges have proven as controversial as the underlying problems. Charter schools — public schools with fewer restrictions, operated by private organizations — were introduced to address some of these issues by providing “school choice.” Charters, however, have been criticized for failing to meet students with disabilities and English Language Learners; they are seen by some as more of an attack on public unions than as education initiatives, and as fundamentally flawed by pitting schools against each other.

Recent desegregation attempts in NYC’s top performing schools has been criticized for unfairly impacting Asian American students, who are well represented in the top schools, but themselves often come from poorer, immigrant families.

Data analysis, data science, and data-driven decision making has been gaining momentum as one tool in improving the NYC educational system through greater insight and accountability. As part of a larger open data initiative, the City publishes a lot of data about its schools and its students. Among other data, the City releases school-level test results for Math and English Language Arts (ELA). These results can be analyzed for different demographic groups, including by race/ethnicity, gender, income, students with disabilities, and English Language Learners. The data analyzed in this case study reports on the ELA test results for the years 2013-2017, for “all students”, at the school level. The results reported at New York State statewide assessments given in grades 3-8 (to, generally, students age 8-13). The data file (ela-all-2013_18.js) is based on data released on the NYC DOE website. The Math and ELA exams are aligned to the Common Core standards. The ELA exam includes reading passages and multiple choice, short answer, and extended answer (essay) responses. Student results are categorized as a 1, 2, 3, or 4 where 1 is the lowest result and 4 is the highest result. Students scoring 3 or 4 are considered proficient in the subject area.

Lastly, while the tests are administered to every student in the public schools there has been a significant resistant to the tests in some schools and districts, statewide, in the form of “opting out” where students and parents choose not to participate in the testing due to concerns about how test results are used to punish schools, teachers, and students; questions over the validity of the measures; and beliefs that high stakes testing corrupts learning and siphons resources from more authentic and valuable educational goals.

The functions annotated in school-report.js demonstrate some common programming patterns for working with arrays of data, and array traversal — using a for loop to iterate over each item in an array. Notice that all of the functions that work with the testData are pure functions. They do not have side effects — they don’t modify any variables outside of the function, only communicating through input function parameters and output with the return statement. To make it easier to understand these pure functions, each function has a comment header which indicates what values and types of data are expected for the function parameters and are returned by the return statement.

The set of reporting functions at the end of program, however, are not pure functions. They provide user output using console.log. This printing to the console is a side effect of the function.

View the “School Data Report” repl

### Case Study: school-report.js

/**
* File: school-report.js
* Demonstrates common patterns for using for loops
* and arrays, using the NYC school data file and the
* school data object.
*
* Properties of TestResult objects:
*
* - id: string, a unique id that has the school district, boro,
*   and school number,  ex: "01M015"
* - name: string, the full school name, ex:"P.S. 015 Roberto Clemente"
* - grade: integer, the grade level for the test results, grades 3-8
* - year: integer, the year the test was taken. The data includes all
*   results from  2013-2017
* - numTested: integer, the number of students taking the test at this
* - level1: integer, the number of students scoring a one (1), lowest
* - level2: integer, the number of students scoring a two (2)
* - level3: integer, the number of students scoring a three (3)
* - level4: integer, the number of students scoring a four (4), highest
* - district: integer, the NYC DOE school district, districts are smaller
*   geographic areas consisting of several schools, with their own, more
*   local administration. They are numbered 1-32, with disctrict 75 as a
*   citywide special district designed to help students with disabilities
*   and special needs
*   boro: string, one of the five boroughs:
*   Manhattan, Bronx, Brooklyn, Queens, Staten Island
* - avg: float, the average score for this school, for the given year
*   and grade level.  is NaN if the results are not valid
*
* The functions in this program work on test data stored as an array
* of TestResult data objects. An example of a single object:
* {
*   "id": "13K009",
*   "name": "P.S. 009 Teunis G. Bergen",
*   "year": 2016,
*   "numTested": 107,
*   "level1": 20,
*   "level2": 28,
*   "level3": 22,
*   "level4": 37,
*   "district": 13,
*   "boro": "Brooklyn",
*   "avg": 2.710280373831776
* },
*/

import testData from "./data/ela-all-2013_18.js";

/**
* totalTested finds the total number of students
* tested in data set data
* This is an example of the counter pattern.
* @param data, an array of data objects where each
*        objcect _must_ have a property numTested
* @return int, the sum of all test takers
*/
function totalTested(data) {
let total = 0;
for (let i = 0; i < data.length; i++) {
total += data[i].numTested;
}
}

/**
* totalTestedGrade finds the total number of students
* tested in the data set in a give grade level.
* This is an example of the counter pattern
* with a conditional check.
* @param data, an array of data objects where each
*        objcect _must_ have the properties
*        numTested and grade
* @param grade, an int in the range 3..8 to indicate
*        which grade to search for
* @return int, the total number students of students tested
*         in the given grade
*/
let total = 0;
for (let i = 0; i < data.length; i++) {
total += data[i].numTested;
}
}
}

/**
* averageTestScores finds the average test scores
* in the dataset data for a single grade
* in a single test year.
* It's a more complex example of a real solution
* programmed using the counter pattern.
* @param data, an array of data objects where each
*        objcect _must_ have the properties
*        numTested and grade
* @param grade, an int in the range 3..8 to indicate
*        which grade to search for
* @param year, an int
* @return float, the mean average test result
*         (in the range 0..4) of all results that match
*         the grade and year criteria
*/
function averageTestScores(data, grade, year) {
let sum = 0;
let numResults = 0;
for (let i = 0; i < data.length; i++) {
let testResults = data[i];
&& testResults.year === year
&& testResults.avg !== NaN) {
sum += testResults.avg;
numResults++;
}
}

return sum / numResults;
}

/**
* findHighestAvgScore searches through
* the test results in data and returns
* the test result data object with the highest
* number in the avg property.
* @param data, an array of data objects where each
*        object _must_ have the property
*        avg to indicate the average test
*        score for that data record
* @return object, the test result data object with
*         the highest average score in the dataset
*/
function findHighestAvgScore(data) {
let highestResult = data[0];
for (let i = 1; i < data.length; i++) {
if (data[i].avg > highestResult.avg) {
highestResult = data[i];
}
}
return highestResult;
}

/**
* filterBetterThanLimit returns a sub-array
* based on array data, with only the test result
* elements of data where the average test score
* is higher than limit.
* @param data, an array of data objects where each
*        object _must_ have the property
*        avg to indicate the average test
*        score for that data record
* @param limit, a float in the range 0..4 to indicate
*        the lower limit for test results to return
* @return array, an array of test result objects, all of
*         which will have a higher average test score
*         than limit
*/
function filterBetterThanLimit(data, limit) {
let matchingResults = [];
for (let i = 0; i < data.length; i++) {
if (data[i].avg > limit) {
matchingResults.push(data[i]);
}
}
return matchingResults;
}

// _________________________________________________
// ============================= REPORTING FUNCTIONS
// ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾

console.log("\n------------------------------------");
console.log(title);
console.log("------------------------------------\n");
}

function reportAveragesForFirstCohort() {

let r13 = averageTestScores(testData, 4, 2013).toFixed(2);
let r14 = averageTestScores(testData, 5, 2014).toFixed(2);
let r15 = averageTestScores(testData, 6, 2015).toFixed(2);
let r16 = averageTestScores(testData, 7, 2016).toFixed(2);
let r17 = averageTestScores(testData, 8, 2017).toFixed(2);

header("TREND OF SCORES FOR 2013 4TH GRADE");

console.log(
Reporting on the ELA test result trend for the
cohort of who were in 4th grade in 2013.
);

console.log("Average ELA 2013:", r13);
console.log("Average ELA 2014:", r14);
console.log("Average ELA 2015:", r15);
console.log("Average ELA 2016:", r16);
console.log("Average ELA 2017:", r17);

}

function topPerformers() {
header("TOP PERFORMING SCHOOLS (AVG > 3.9)");

let results = filterBetterThanLimit(testData, 3.9);
for(let i = 0; i < results.length; i++) {
let r = results[i];
console.log(
${i + 1}.${r.name}
average score: ${r.avg.toFixed(2)}${r.numTested} students in grade ${r.grade} in${r.year});
}
}

function main() {
header("SCHOOL TEST DATA REPORT");
console.log("Total students tested:", totalTested(testData));

let highest = findHighestAvgScore(testData);
console.log(
The highest average score results were for the students
in grade ${highest.grade} at${highest.name} in ${highest.year}.${highest.numTested} students had an average score of ${highest.avg}. ); reportAveragesForFirstCohort(); topPerformers(); header("REPORT COMPLETE"); } main(); ## School Data Exercises Fork the SchoolData repl https://repl.it/@mcuringa/SchoolData to complete these exrcises. 1. Write a function using the search pattern that finds the finds the highest average test score for a result where at least a minimum number of students took the exam. You can modify findHighestAvgScore so that it has a second parameter, minStudents. 2. Using the same search pattern write a function that finds the lowest test result, it should also have a parameter for minStudents. 3. Use the filter pattern to write a function findByBorough(data, boro) that returns an array of test results for schools in borough boro. 4. Consider the data given. Write a reporting function (and other necessary code) that explores a problem and reports an interesting result. You may use reportAveragesForFirstCohort as an example for the type of report. ### Bonus questions (for 1 point of extra credit each) 1. Find the 5 best test results in the data set. Return an array of the test result objects for these schools. There should be a minimum number of students tested to qualify (specified by a function parameter). 2. Write a function schoolAverages(data) that returns an array of test report objects with exactly one object for each school. grade and year should be set to null because they don’t make sense in this summary. numTested should be the total students tested for that school in the given data. level[1-4] should represent the total students score at that level across years and grades. And avg should have the average (1..4) score for all years and grades. 3. Write a function boroAverages(data, year) that returns an array of objects. The objects must have the following properties: • avg: the average test score for the borough (1..4) • numTested: the total of all students tested • boro: the name of the borough # Objects & Maps ## Key:Value Pairs So far we have looked at sequential data types — strings and arrays — which use integers as indices to access the values they contain. Maps are yet another kind of compound type. It is conventional to use Objects as the mapping type in Javascript, as we have seen in the School Data case study. Javascript also offers a built-in [Map data type] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map), but we will stick with the Object convention for this chapter. Mapped data structures map keys to values. Values can be any type (heterogeneous), just like the elements of an array. Sometimes maps are called associative arrays since they associate a key with a value. When using objects as maps (as we will for most of this chapter), keys should be strings. The Map object in Javascript allows keys to be of any type. As an example, we will create a map to translate English words into Spanish. For this map, the keys are strings. One way to create a map is to start with the empty object and add key:value pairs. The empty object is denoted by {}: ⠕ let eng2sp = {}; ⠕ eng2sp["one"] = "uno"; ⠕ eng2sp["two"] = "dos"; The first assignment creates a map named eng2sp; the other assignments add new key:value pairs to the map. We can print the current value of the map in the usual way: ⠕ console.log(eng2sp); { one: 'uno', two: 'dos' } The key:value pairs of the map are separated by commas. Each pair contains a key and a value separated by a colon. Another way to create a map is to provide a list of key:value pairs using the same syntax as the previous output: ⠕ let eng2sp = {"one": "uno", "two": "dos", "three": "tres"}; It doesn’t matter what order we write the pairs. The values in a map are accessed with keys, not with indices, so there is no need to care about ordering. Here is how we use a key to look up the corresponding value: ⠕ console.log(eng2sp["two"]); dos The key "two" yields the value "dos". Arrays and strings have been called sequences, because their items occur in order. The map is the first compound type that we’ve seen that is not a sequence, so we can’t index or slice a map. ## Map operations The delete statement removes a key:value pair from a map. For example, the following map contains the names of various fruits and the number of each fruit in stock: ⠕ let inventory = {"apples": 430, "bananas": 312, "oranges": 525, "pears": 217}; ⠕ console.log(inventory); { apples: 430, bananas: 312, oranges: 525, pears: 217 } If someone buys all of the pears, we can remove the entry from the map: ⠕ delete inventory["pears"]; ⠕ console.log(inventory); { apples: 430, bananas: 312, oranges: 525 } Or if we’re expecting more pears soon, we might just change the value associated with pears: ⠕ inventory["pears"] = 0; ⠕ console.log(inventory); { apples: 430, bananas: 312, oranges: 525, pears: 0 } A new shipment of bananas arriving could be handled like this: ⠕ inventory["bananas"] += 200; ⠕ console.log(inventory); inventory["bananas"] += 200 ## Object utility functions The built in Object library contains many useful functions for working with objects as map datatypes. We can use Object.keys() to return an array of all of the keys in a map. Using the keys, we can iterate through the keys and values in our map. let eng2sp = {"one": "uno", "two": "dos", "three": "tres"}; let keys = Object.keys(eng2sp); for (let i = 0; i < keys.length; i++) { let k = keys[i]; console.log("Got key", k, "which maps to value", eng2sp[k]); } console.log(keys); This produces this output: Got key one which maps to value uno Got key two which maps to value dos Got key three which maps to value tres [ 'one', 'two', 'three' ] It is so common to iterate over the keys in a map that Javascript provides a special syntax for this loop. for (let k in eng2sp) { console.log("Got key", k); } The Object.values() function is similar to keys(); it returns an array containing all of the map’s objects: ⠕ Object.values(eng2sp); => [ 'uno', 'dos', 'tres' ] The Object.entries() function returns an array of key:value pair arrays.  ⠕ Object.entries(eng2sp); [ [ 'one', 'uno' ], [ 'two', 'dos' ], [ 'three', 'tres' ] ] Combining Object.entries() with a Javascript syntax for destructuring assignment, we can easily iterate over the keys and values of a map. for (let [k, v] of Object.entries(eng2sp)) { console.log(k, v); } This produces: one uno two dos three tres This simple example introduces two new Javascript structures. Destructuring takes the values of an array on the right hand of the assignment operator and assigns them to multiple individual variables on the left hand side of the operation. let [a, b] = [1, 2] creates two new variables, a and b with the values 1 and 2 respectively. We also use the special for…of syntax for this loop. This is a compact form of our usual array iteration loop that doesn’t require (or afford) a loop index. Other than iterating through key:value pairs of maps, we will use the standard for loop for array iteration. You can read more about for…of in the docs. If we try to access a key that isn’t in our map, Javascript yields the special undefined value. Javascript offers the in operator specifically to allow us to test if a key exists in a map. in will always return a boolean result (true or false) indicating the existence of a key. ⠕ eng2sp["one"] 'uno' ⠕ "six" in eng2sp false Later in the chapter we will see some examples where we use this technique to determine if we should update an existing entry in a map or create a new entry. Have a look at this video if you want to see some of the map basics in action. ## Aliasing and copying As in the case of arrays, because maps are mutable, we need to be aware of aliasing. Whenever two variables refer to the same object, changes to one affect the other. If we want to modify a map and keep a copy of the original, use the copy method. For example, opposites is a map that contains pairs of opposites: ⠕ let opposites = {"up": "down", "right": "wrong", "yes": "no"}; ⠕ let alias = opposites; ⠕ let copy = Object.assign(opposites); // a shallow copy alias and opposites refer to the same object; copy refers to a fresh copy of the same map. If we modify alias, opposites is also changed: ⠕ alias["right"] = "left"; ⠕ opposites["right"]; 'left' If we modify copy, opposites is unchanged: ⠕ copy["right"] = "privilege"; ⠕ opposites["right"]; 'left' ## Counting letters In the exercises in in the Strings chapter, we wrote a function that counted the number of occurrences of vowels in a string. A more general version of this problem is to form a frequency table of the letters in the string, that is, how many times each letter appears. Such a frequency table might be useful for compressing a text file. Because different letters appear with different frequencies, we can compress a file by using shorter codes for common letters and longer codes for letters that appear less frequently. Maps provide an elegant way to generate a frequency table: let letterCounts = {}; let word = "Mississippi"; word = word.toLowerCase(); for (let i = 0; i < word.length; i++) { let letter = word[i]; if (letter in letterCounts) { letterCounts[letter]++; } else { letterCounts[letter] = 1; } } console.log(letterCounts); Outputs: { M: 1, i: 4, s: 4, p: 2 } We start with an empty map. For each letter in the string, we find the current count (possibly zero) and increment it. At the end, the map contains pairs of letters and their frequencies. We use a Boolean if/else to determine if the key exists in our map. _If the key is already in the map we increment the count, else we assign an initial value of 1 to that key. Note that we call toLowerCase() on our string because keys, as you should expect, are case-sensitive. It might be more appealing to display the frequency table in alphabetical order. We can do that with the Object.keys() function in the Object library and then calling sort() on our array of keys. We can add this code to our example above in order to print out the frequency map of letters in alphabetical order. let keys = Object.keys(letterCounts); keys.sort(); for(let i = 0; i < keys.length; i++) { let letter = keys[i]; console.log(${letter}: ${letterCounts[letter]}); } See the interactive example online at https://repl.it/@mcuringa/MapLetterFrequency. ## Glossary map A collection of key:value pairs that maps from keys to values. The keys should be a string, and the associated value can be of any type. immutable data value A data value which cannot be modified. Assignments to immutable datatypes have no effect or cause a runtime error. key A data item that is mapped to a value in a map. Keys are used to look up values in a map. Each key must be unique across the map. key:value pair One of the pairs of items in a map. Values are looked up in a map by key. mapping type A mapping type is a data type comprised of a collection of keys and associated values. Javascript’s objects are used as mapping types in this chapter. Objects implement the associative array abstract data type. mutable data value A data value which can be modified. The types of all mutable values are compound types. Arrays and maps are mutable; strings and numbers are not. # Web GUIs ## GUI: Graphical User Interface A GUI or graphical user interface is the main way that most of us interact with computers most of the time. The standards for graphical computing are well known: clicking buttons and icons, scrolling windows, reading images and text, etc. When we created our Turtle programs, we were programming GUIs. Most of the examples in this text, however have used text interfaces or Command Line Interfaces (CLI). With a CLI, the user receives computer output through text on the screen, and sends input to the program by entering text. In this chapter, we introduce a Javascript-based library for creating GUIs web applications. ## How the web works (the super brief version) There are three computer languages that form the base for any web page. They are HTML, CSS, and Javascript. Hypertext markup language (HTML) describes the type of content on a web page. HTML describes many different types of content. You are familiar with most of them: - text: titles, paragraphs, lists, etc - media: images, videos, audio, animation graphics - links: that allow navigation to different areas of the web - form elements: buttons, input boxes, checkboxes, and other elements that users to input information - tables: that display grids of information Other HTML elements are more structural, they divide web pages into sections (like headers and footers). Cascading style sheets (CSS), control the layout of the content described by the HTML. CSS can be used to change the font or text size, add background images to elements, space and size different containers, and, generally create useful and aesthetic interfaces. A single HTML document can work with different CSS styles, allowing it to adapt to different use cases. One set of styles can control layout for mobile phones, another for laptops, and yet another for print. Javascript is the only programming language of the three languages discussed here. It’s the only of the group that uses variables and controls the flow of execution with loops and Boolean conditions. At this point in the book, we are familiar with many of the programming aspects of Javascript. For the web, Javascript can interact with user input, and dynamically change the content and HTML structure on a page. While some, small websites are static — meaning that all of the content and HTML is written by hand in a text editor like the one in repl.it — most website pull the content from databases or other data files. We have begun to see how Javascript can interact with larger sets of data, now we will see how Javascript can be used to display this data on the web, to create dynamic websites that change when the data is changed. ## JS GUI JS GUI is a Javascript library or module that is being written to accompany the examples in this book. There are many powerful Javascript frameworks, like React (developed by Facebook) and Angular (developed by Google), used by professional software developers to create complex, interactive web applications. However, these professional frameworks aren’t necessarily the best or easiest to start with. To use JS GUI, you need the following: • a website like this demo repl • an html page that runs your Javascript file (e.g. index.html) • a local version of the jsgui.js library The following code examples assume such a set-up. ## Basic Elements JS GUI provides a series of functions for creating and adding graphical elements to a web page. After importing the library, you can easily start adding elements. The following code creates a web site with the text, Hello, world. import jsgui from "./lib/jsgui.js"; jsgui.add("Hello, world"); JS GUI provides functions to create titles, (level 1-6), images, and paragraphs of text. New lines can be created with br() and horizontal rules with hr(). This code uses titles, text, images, breaks, and rules. import jsgui from "./lib/jsgui.js"; let catPic = jsgui.img("cat.jpg", "a black cat"); let dogPic = jsgui.img("dog.jpg", "a shaggy Newfoundland dog"); jsgui.add(jsgui.h1("Cats and Dogs")); jsgui.add(jsgui.p("Do you prefer cats or dogs?")); jsgui.add(jsgui.h4("Cat people")); jsgui.add(catPic); jsgui.add(jsgui.br()); jsgui.add("Some people like cats. Cats are quiet, playful, soft, and sweet."); jsgui.add(jsgui.br()); jsgui.add(jsgui.hr()); jsgui.add(jsgui.br()); jsgui.add(jsgui.h4("Dog people")); jsgui.add(dogPic); jsgui.add(jsgui.br()); jsgui.add(Some people like dogs. Dogs are loyal friends and companions, sad to see you leave and ecstatic when you get home.); The img(url, alt) function has two parameters, the first is the URL of the image. In this case, it’s in the same location as our code, so we only need the file name: cat.jpg. If it was on another server, we could put the full URL, something like https://www.example.com/img/cat.jpg. THe alt parameter is a short text description of the image that makes the web more useful for users with disabilities, such as visual impairment. For the catPic and dogPic we save the image into a variable before calling add() to place it on the web page. Th rest of the html elements in this code example are composed directly with the add() function. h1() and h4() create a level 1 header and level 4 header respectively. p() creates a paragraph of text. br() is a line break that forces a new line. Vertical whitespace in HTML is (usually) ignored when the web browser lays out a page. hr() creates a horizontal rule (line) across the page. ## JS GUI, Arrays, and Objects JS GUI has some helper functions that makes it easy to display mapped data and arrays of data. For the key-value pairs in a map, JS GUI uses the HTML definition list element. A definition list (<dl>) describes contents that have a term and a definition. The dl() function maps the keys to terms and the values to definitions. // ... let pet = { name: "Sparkle Swan Fireworks", type: "Cat", age: "3", breed: "American Short Hair" } jsgui.add(jsgui.dl(pet)); Arrays of data can be quickly laid out as tables. The example below uses an array of arrays, where each element of animalsOnScreen is an array. jsgui.table(data, header) takes the data as the first argument. If an array is passed for the header argument, table() will use that data to make bold column headers. Although not used here, data can also be an array of data maps. If this is the case, only the values from the map are displayed in the table rows. // ... let animalsOnScreen = [ ["Name", "Type", "Breed", "Film/Show"], ["Rin Tin Tin", "Dog", "German Shepherd", "Various"], ["Lassie", "Dog", "Collie", "Lassie"], ["Mrs. Norris", "Cat", "Maine Coon", "Harry Potter"], ["Flipper", "Dolphin", "bottlenose", "Flipper"] ]; let table = jsgui.table(animalsOnScreen.slice(1), animalsOnScreen[0]); jsgui.add(table); This example creates an array with 4 columns and 5 elements. Since the 0-th element contains the header data, slice(1) is used to exclude that row when table() is called, and the array at animalsOnScreen[0] is passed as the header argument. ## Code Listing: JS GUI Demo ### Complex compositions with containers Web pages, like software programs, can be made more flexible using the decomposition strategy of breaking the problem (the page layout) into smaller parts. HTML offers a number of block elements that contain other elements (including blocks). Using Javascript, we can write functions that return a group of elements in one of these containers. We can make our code more abstract, where functions can use the same layout for different content. Alternatively, we can make functions that are re-usable, such as returning headers, footers, and navigation elements that can be used across several web pages. The examples in this code listing use many, but not all of the layout features of JS GUI. ### Case Study: JSGUI Demo /** * index.js is the default script for the JSGUI Demo Site * It demonstrates some of the main layout functions included * in the js gui package. */ import jsgui from "./lib/jsgui.js"; /** * create a panel about an animal with a title, img, and caption */ function animalDetail(title, img, text) { let container = jsgui.div(); jsgui.append(container, jsgui.h4(title), img, jsgui.br(), text); return container; } /** * create a section with all of the elements for Cats or Dogs */ function catsOrDogs() { let sec = jsgui.section(); let catPic = jsgui.img("cat.jpg", "a black cat"); let dogPic = jsgui.img("dog.jpg", "a shaggy Newfoundland dog"); let catPeople = animalDetail("Cat people", catPic, "Some people like cats. Cats are quiet, playful, soft, and sweet."); let dogPeople = animalDetail("Dog people", dogPic, "Some people like dogs: loyal friends and quick with a trick."); let grid = jsgui.grid(2); jsgui.addToGrid(grid, 1, catPeople); jsgui.addToGrid(grid, 2, dogPeople); jsgui.append(sec, jsgui.h2("Cats and Dogs"), jsgui.p("Do you prefer cats or dogs?"), grid, jsgui.hr()); return sec; } /** * create the Animals on Screen section */ function animalActors() { let sec = jsgui.section(); let animalsOnScreen = [ ["Name", "Type", "Breed", "Film/Show"], ["Rin Tin Tin", "Dog", "German Shepherd", "Various"], ["Lassie", "Dog", "Collie", "Lassie"], ["Mrs. Norris", "Cat", "Maine Coon", "Harry Potter"], ["Flipper", "Dolphin", "Bottlenose", "Flipper"] ]; let table = jsgui.table(animalsOnScreen.slice(1), animalsOnScreen[0]); jsgui.append(sec, jsgui.h2("Animals on the Screen"), table, jsgui.hr()); return sec; } /** * create a page header */ function header() { let h = jsgui.header(); jsgui.append(h, jsgui.h1("Animals On Screen")); jsgui.append(h, jsgui.h5("A demo of the JS GUI library")); let about = "JS GUI is [Free Open Source Software](https://fsf.org)" + "for teaching and learning to program web-based JS guis. " + "It was created by Robby Lucia and Matt Curinga to accompany " + "the open textbook, _Think JS_. " + "[[read online](http://mcuringa.github.com/think-js)] " + "[[source](https://github.com/mcuringa/think-js)]."; about = jsgui.md(about); jsgui.append(h, about); jsgui.append(h, jsgui.hr()); return h; } // start our program function main() { jsgui.add( header(), catsOrDogs(), animalActors() ); } main(); # React Web Programming ## Code Listing: SpellCaster ### Reacting to user interaction This code listing steps through the process of making a moderately complex web user interface that reacts to user actions. It presents a list of spells and allows the user to filter the list by checking/unchecking a series of checkbox form elements. The code must keep track of which boxes are checked in the React Object state. The list of spells must update dynamically when changes are detected. This is what we mean by a reactive interface. ### Case Study: SpellCaster Spells import React, { Component } from 'react'; import { Link } from "react-router-dom"; import _ from "lodash"; import { ClassIcon } from "./Icons"; import spells from "./data/spells.json"; import details from "./res/wireframes/spell-detail.png"; class SpellTable extends Component { constructor(props) { super(props); let filters = { bard: true, cleric: true, druid: true, monk: true, paladin: true, ranger: true, sorcerer: true, warlock: true, wizard: true } this.state = { spells: [], charClassFilters: filters }; this.toggleFilter = this.toggleFilter.bind(this); this.clearFilters = this.clearFilters.bind(this); this.allCharClasses = this.allCharClasses.bind(this); } componentWillMount() { let spellList = _.sortBy(spells, "level_int"); this.setState({ spells: spellList }); } toggleFilter(charClass) { let filters = this.state.charClassFilters; filters[charClass] = !filters[charClass]; //toggle the filter this.setState({charClassFilters: filters}); } clearFilters() { let filters = this.state.charClassFilters; for(let k in filters) { filters[k] = false; } this.setState({charClassFilters: filters}); } allCharClasses() { let filters = this.state.charClassFilters; for(let k in filters) { filters[k] = true; } this.setState({charClassFilters: filters}); } render() { const th = (header, index) => { return (<th key={index}>{header}</th>) }; let headers = [ "Spell", "Level", "School", "Casting Classes" ]; headers = headers.map(th); let filters = this.state.charClassFilters; let spells = filterSpellsByCharClass(this.state.spells, filters); const rows = spells.map(SpellRow); return ( <section id="Spells"> <h2>Spells</h2> <h5 className="text-primary"> Filter list <button type="button" className="btn btn-link btn-sm" onClick={this.clearFilters}>[clear]</button> <button type="button" className="btn btn-link btn-sm" onClick={this.allCharClasses}>[all]</button> </h5> <form> <IconCheckBox onChange={this.toggleFilter} isActive={filters["bard"]} charClass="bard" /> <IconCheckBox onChange={this.toggleFilter} isActive={filters["cleric"]} charClass="cleric" /> <IconCheckBox onChange={this.toggleFilter} isActive={filters["druid"]} charClass="druid" /> <IconCheckBox onChange={this.toggleFilter} isActive={filters["monk"]} charClass="monk" /> <IconCheckBox onChange={this.toggleFilter} isActive={filters["paladin"]} charClass="paladin" /> <IconCheckBox onChange={this.toggleFilter} isActive={filters["ranger"]} charClass="ranger" /> <IconCheckBox onChange={this.toggleFilter} isActive={filters["sorcerer"]} charClass="sorcerer" /> <IconCheckBox onChange={this.toggleFilter} isActive={filters["warlock"]} charClass="warlock" /> <IconCheckBox onChange={this.toggleFilter} isActive={filters["wizard"]} charClass="wizard" /> </form> <table className="table table-hover table-sm"> <thead><tr>{headers}</tr></thead> <tbody>{rows}</tbody> </table> </section> ) } } function filterSpellsByCharClass(spells, classes) { let t = []; function isActive(spellCasters) { for(let i = 0; i < spellCasters.length; i++) { let charClass = spellCasters[i].toLowerCase(); if(classes[charClass]) { return true; } } return false; } for(let i = 0; i < spells.length; i++) { const spell = spells[i]; const spellCasters = spell["class"].split(", "); if(isActive(spellCasters)) { t.push(spell); } } return t; } function IconCheckBox(props) { function toggle() { props.onChange(props.charClass); } return ( <span key={toggle_${props.charClass}} className="form-check form-check-inline">
<input className="form-check-input"
type="checkbox"
checked={props.isActive}
onChange={toggle} />
<ClassIcon charClass={props.charClass} /> {props.charClass}
</span>
)
}

function SpellRow(spell) {

const check = (casterClass) => {
const spellCasters = spell["class"].split(", ");
if (_.includes(spellCasters, casterClass)) {
return (
<abbr title={casterClass}>
<ClassIcon charClass={casterClass.toLowerCase()} />
</abbr>
)
}
return null;
}

const level = spell.level_int || "C";
return (

<tr key={spell._id}>
<td>{level}</td>
<td>{spell.school}</td>
<td>
{check("Bard")}
{check("Cleric")}
{check("Druid")}
{check("Ranger")}
{check("Sorcerer")}
{check("Warlock")}
{check("Wizard")}
</td>
</tr>
);
}

export { SpellTable };



# Appendices

## Code templates, solutions, and examples

### Using repl.it

Online code examples in this book are hosted on https://repl.it. Called “repls”, these source files and programs can be edited and run online, and can be easily forked (remixed) and shared. Several types of repls are available: blank templates for working on practice exercises and labs, solutions to exercise problems, and longer code listings that appear in the book.

We recommend that you make a free account on repl.it to fully work with the examples, however, you can run and edit the programs as an anonymous user. You cannot save your work without an account.

## Preface to previous edition

By Jeffrey Elkner

This book owes its existence to the collaboration made possible by the Internet and the free software movement. Its three authors—a college professor, a high school teacher, and a professional programmer—never met face to face to work on it, but we have been able to collaborate closely, aided by many other folks who have taken the time and energy to send us their feedback.

We think this book is a testament to the benefits and future possibilities of this kind of collaboration, the framework for which has been put in place by Richard Stallman and the Free Software Foundation.

## How and why I came to use Python

In 1999, the College Board’s Advanced Placement (AP) Computer Science exam was given in C++ for the first time. As in many high schools throughout the country, the decision to change languages had a direct impact on the computer science curriculum at Yorktown High School in Arlington, Virginia, where I teach. Up to this point, Pascal was the language of instruction in both our first-year and AP courses. In keeping with past practice of giving students two years of exposure to the same language, we made the decision to switch to C++ in the first year course for the 1997-98 school year so that we would be in step with the College Board’s change for the AP course the following year.

Two years later, I was convinced that C++ was a poor choice to use for introducing students to computer science. While it is certainly a very powerful programming language, it is also an extremely difficult language to learn and teach. I found myself constantly fighting with C++’s difficult syntax and multiple ways of doing things, and I was losing many students unnecessarily as a result. Convinced there had to be a better language choice for our first-year class, I went looking for an alternative to C++.

I needed a language that would run on the machines in our GNU/Linux lab as well as on the Windows and Macintosh platforms most students have at home. I wanted it to be free software, so that students could use it at home regardless of their income. I wanted a language that was used by professional programmers, and one that had an active developer community around it. It had to support both procedural and object-oriented programming. And most importantly, it had to be easy to learn and teach. When I investigated the choices with these goals in mind, Python stood out as the best candidate for the job.

I asked one of Yorktown’s talented students, Matt Ahrens, to give Python a try. In two months he not only learned the language but wrote an application called pyTicket that enabled our staff to report technology problems via the Web. I knew that Matt could not have finished an application of that scale in so short a time in C++, and this accomplishment, combined with Matt’s positive assessment of Python, suggested that Python was the solution I was looking for.

## Finding a textbook

Having decided to use Python in both of my introductory computer science classes the following year, the most pressing problem was the lack of an available textbook.

Free documents came to the rescue. Earlier in the year, Richard Stallman had introduced me to Allen Downey. Both of us had written to Richard expressing an interest in developing free educational materials. Allen had already written a first-year computer science textbook, How to Think Like a Computer Scientist. When I read this book, I knew immediately that I wanted to use it in my class. It was the clearest and most helpful computer science text I had seen. It emphasized the processes of thought involved in programming rather than the features of a particular language. Reading it immediately made me a better teacher.

How to Think Like a Computer Scientist was not just an excellent book, but it had been released under the GNU public license, which meant it could be used freely and modified to meet the needs of its user. Once I decided to use Python, it occurred to me that I could translate Allen’s original Java version of the book into the new language. While I would not have been able to write a textbook on my own, having Allen’s book to work from made it possible for me to do so, at the same time demonstrating that the cooperative development model used so well in software could also work for educational materials.

Working on this book for the last two years has been rewarding for both my students and me, and my students played a big part in the process. Since I could make instant changes whenever someone found a spelling error or difficult passage, I encouraged them to look for mistakes in the book by giving them a bonus point each time they made a suggestion that resulted in a change in the text. This had the double benefit of encouraging them to read the text more carefully and of getting the text thoroughly reviewed by its most important critics, students using it to learn computer science.

For the second half of the book on object-oriented programming, I knew that someone with more real programming experience than I had would be needed to do it right. The book sat in an unfinished state for the better part of a year until the open source community once again provided the needed means for its completion.

I received an email from Chris Meyers expressing interest in the book. Chris is a professional programmer who started teaching a programming course last year using Python at Lane Community College in Eugene, Oregon. The prospect of teaching the course had led Chris to the book, and he started helping out with it immediately. By the end of the school year he had created a companion project on our Website at http://openbookproject.net (Python for Fun)[http://openbookproject.net/py4fun>] and was working with some of my most advanced students as a master teacher, guiding them beyond where I could take them.

## Introducing programming with Python

The process of translating and using How to Think Like a Computer Scientist for the past two years has confirmed Python’s suitability for teaching beginning students. Python greatly simplifies programming examples and makes important programming ideas easier to teach.

The first example from the text illustrates this point. It is the traditional hello, world program, which in the Java version of the book looks like this:

class Hello
{
public static void main (String[] args)
{
System.out.println ("Hello, world.");
}
}

in the Python version it becomes:

print("Hello, World!")

Even though this is a trivial example, the advantages of Python stand out. Yorktown’s Computer Science I course has no prerequisites, so many of the students seeing this example are looking at their first program. Some of them are undoubtedly a little nervous, having heard that computer programming is difficult to learn. The Java version has always forced me to choose between two unsatisfying options: either to explain the class Hello, public static void main, String[] args, {, and }, statements and risk confusing or intimidating some of the students right at the start, or to tell them, Just don’t worry about all of that stuff now; we will talk about it later, and risk the same thing. The educational objectives at this point in the course are to introduce students to the idea of a programming statement and to get them to write their first program, thereby introducing them to the programming environment. The Python program has exactly what is needed to do these things, and nothing more.

Comparing the explanatory text of the program in each version of the book further illustrates what this means to the beginning student. There are seven paragraphs of explanation of Hello, world! in the Java version; in the Python version, there are only a few sentences. More importantly, the missing six paragraphs do not deal with the big ideas in computer programming but with the minutia of Java syntax. I found this same thing happening throughout the book. Whole paragraphs simply disappear from the Python version of the text because Python’s much clearer syntax renders them unnecessary.

Using a very high-level language like Python allows a teacher to postpone talking about low-level details of the machine until students have the background that they need to better make sense of the details. It thus creates the ability to put first things first pedagogically. One of the best examples of this is the way in which Python handles variables. In Java a variable is a name for a place that holds a value if it is a built-in type, and a reference to an object if it is not. Explaining this distinction requires a discussion of how the computer stores data. Thus, the idea of a variable is bound up with the hardware of the machine. The powerful and fundamental concept of a variable is already difficult enough for beginning students (in both computer science and algebra). Bytes and addresses do not help the matter. In Python a variable is a name that refers to a thing. This is a far more intuitive concept for beginning students and is much closer to the meaning of variable that they learned in their math courses. I had much less difficulty teaching variables this year than I did in the past, and I spent less time helping students with problems using them.

Another example of how Python aids in the teaching and learning of programming is in its syntax for functions. My students have always had a great deal of difficulty understanding functions. The main problem centers around the difference between a function definition and a function call, and the related distinction between a parameter and an argument. Python comes to the rescue with syntax that is nothing short of beautiful. Function definitions begin with the keyword def, so I simply tell my students, When you define a function, begin with def, followed by the name of the function that you are defining; when you call a function, simply call (type) out its name. Parameters go with definitions; arguments go with calls. There are no return types, parameter types, or reference and value parameters to get in the way, so I am now able to teach functions in less than half the time that it previously took me, with better comprehension.

Using Python improved the effectiveness of our computer science program for all students. I saw a higher general level of success and a lower level of frustration than I experienced teaching with either C++ or Java. I moved faster with better results. More students left the course with the ability to create meaningful programs and with the positive attitude toward the experience of programming that this engenders.

## Building a community

I have received email from all over the globe from people using this book to learn or to teach programming. A user community has begun to emerge, and many people have been contributing to the project by sending in materials for the companion Website at http://openbookproject.net/pybiblio.

With the continued growth of Python, I expect the growth in the user community to continue and accelerate. The emergence of this user community and the possibility it suggests for similar collaboration among educators have been the most exciting parts of working on this project for me. By working together, we can increase the quality of materials available for our use and save valuable time. I invite you to join our community and look forward to hearing from you. Please write to me at jeff@elkner.net.

Jeffrey Elkner
Governor’s Career and Technical Academy in Arlington
Arlington, Virginia

## The Rhodes Local Edition (RLE) (Version of August, 2012)

By Peter Wentworth

A colleague and friend, Peter Warren, once made the remark that learning introductory programming is as much about the environment as it is about the programming language.

I’m a big fan of IDEs (Integrated Development Environments).
I want help to be integrated into my editor, as a first-class citizen, available at the press of a button. I want syntax highlighting. I want immediate syntax checking, and sensible autocompletion. I’d like an editor that can fold function bodies or regions of code away, because it promotes and encourages how we build mental abstractions.

I’m especially keen on having a single-stepping debugger and breakpoints with code inspection built in. We’re trying to build a conceptual model of program execution in the student’s mind, so I find most helpful for teaching to have the call stack and variables explicitly visible, and to be able to immediately inspect the result of executing a statement.

My philosophy, then, is not to look for a language to teach, but to look for a combination of IDE and language that are packaged together, and evaluated as a whole.

I’ve made some quite deep changes to the original book to reflect this (and various other opinionated views that I hold), and I have no doubt that more changes will follow as we mature our course.

Here are some of the key things I’ve approached differently:

• Our local situation demands that we have a large number of service course students in an introductory course of just 3 weeks, and then we get another semester of teaching with those going into our mainstream program. So the book is in two parts: we’ll do the first five chapters in the big “get your toes wet” course, and the rest of the material in a separate semester.
• We’re using Python 3. It is cleaner, more object oriented, and has fewer ad-hoc irregularities than earlier versions of Python.
• We’re using PyScripter as our IDE, on Windows. And it is hardwired into parts of these notes, with screenshots, etc.
• I’ve dropped GASP.
• For graphics we start with the Turtle module.
As things move along, we use PyGame for more advanced graphics.
• I’ve introduced some event-driven programming using the turtle.
• I have tried to push more object-oriented notions earlier, without asking students to synthesize objects or write their own classes. So, for example, in the chapter about the turtle, we create multiple instances of turtles, talk about their attributes and state (color, position, etc), and we favour method-call style to move them around, i.e. tess.forward(100). Similarly, when we use random numbers, we avoid the “hidden singleton generator” in the random module — we prefer to create an instance of a generator, and invoke methods on the instance.
• The ease of constructing lists and the for loop seem to be winners in Python, so rather than use the traditional command-line input for data, I’ve favoured using loops and lists right up front, like this:
friends = ["Zoe", "Joe", "Bill"]
for f in friends:
invitation = "Hi " + f + ".  Please come to my party on Saturday!"
print(invitation)

This also means that I bumped range up for early exposure.
I envisage that over time we’ll see more opportunities to exploit “early lists, early iteration” in its most simple form.

• I dumped doctest: it is too quirky for my liking. For example, it fails a test if the spacing between list elements is not precisely the same as the output string, or if Python prints a string with single quotes, but you wrote up the test case with double quotes. Cases like this also confused students (and instructors) quite badly:

"""
>>> xs = [2,3,4]
9
"""
return

If you can explain the difference in scope rules and lifetimes between the parameter xs and the doctest variable xs elegantly, please let me know. Yes, I know doctest creates its own scope behind our back, but it is exactly this black magic that we’re trying to avoid.
From the usual indentation rules, also looks like the doctests are nested inside the function scope, but they are not. Students thought that the parameter had been given its value by the assignment to xs in the doctest!

I also think that keeping the test suite separate from the functions under test leads to a cleaner relationship between caller and callee, and gives a better chance of getting argument passing / parameter concepts taught accurately.

There is a good unit testing module in Python, (and PyScripter offers integrated support for it, and automated generation of skeleton test modules), but it looked too advanced for beginners, because it requires multi-module concepts.

So I’ve favoured my own test scaffolding in Chapter 6 (about 10 lines of code) that the students must insert into whatever file they’re working on.

• I’ve played down command-line input / process / output where possible. Many of our students have never seen a command-line shell, and it is arguably quite intimidating.

• We’ve gone back to a more “classic / static” approach to writing our own classes and objects. Python (in company with languages like Javascript, Ruby, Perl, PHP, etc.) don’t really emphasize notions of “sealed” classes or “private” members, or even “sealed instances”.

So one teaching approach is to allocate each instance as an empty container, and subsequently allow the external clients of the class to poke new members (methods or attributes) into different instances as they wish to.
It is a very dynamic approach, but perhaps not one that encourages thinking in abstractions, layers, contracts, decoupling, etc. It might even be the kind of thing that one could write one of those “x,y,z … considered harmful” papers about.

In our more conservative approach, we put an initializer into every class, we determine at object instantiation time what members we want, and we initialize the instances from within the class. So we’ve moved closer in philosophy to C# / Java on this one.

• We’re moving towards introducing more algorithms earlier into the course. Python is an efficient teaching language — we can make fast progress. But the gains we make there we’d like to invest into deeper problem solving, and more complex algorithms with the basics, rather than cover “more Python features”. Some of these changes have started to find their way in this version, and I’m sure we’ll see more in future.

• We’re interested in issues around teaching and learning. Some research indicates that “intellectual playfulness” is important. The study referenced in the Odds-and-ends workbook at the end just didn’t seem to have anywhere sensible to go in the book, yet I wanted it included. It is quite likely that we’ll allow more issues like this to creep into the book, to try to make it more than just about programming in Python.

## GNU Free Documentation License

Version 1.3, 3 November 2008

Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. https://fsf.org/

Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

#### 0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other functional and useful document “free” in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

#### 1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.

Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.

The “publisher” means any person or entity that distributes copies of the Document to the public.

A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.

The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

#### 2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

You may also lend copies, under the same conditions stated above, and you may publicly display copies.

#### 3. COPYING IN QUANTITY

If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

#### 4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

• A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
• B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
• C. State on the Title page the name of the publisher of the Modified Version, as the publisher.
• D. Preserve all the copyright notices of the Document.
• F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
• G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document’s license notice.
• H. Include an unaltered copy of this License.
• I. Preserve the section Entitled “History”, Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled “History” in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
• J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the “History” section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
• K. For any section Entitled “Acknowledgements” or “Dedications”, Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
• L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
• M. Delete any section Entitled “Endorsements”. Such a section may not be included in the Modified Version.
• N. Do not retitle any existing section to be Entitled “Endorsements” or to conflict in title with any Invariant Section.
• O. Preserve any Warranty Disclaimers.

If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.

You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.

#### 5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements”.

#### 6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

#### 7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

#### 8. TRANSLATION

Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

#### 9. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.

However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.

Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.

Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.

#### 10. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See https://www.gnu.org/licenses/.

Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.

#### 11. RELICENSING

“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.

“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.

“Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.

An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.

The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.

### ADDENDUM: How to use this License for your documents

To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:

    Copyright (C)  YEAR  YOUR NAME.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".

If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with … Texts.” line with this:

    with the Invariant Sections being LIST THEIR TITLES, with the
Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.`

If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.

If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.