Skip to content

Commit 63a20c9

Browse files
committed
First pass over Chapter 8
1 parent 7918bb2 commit 63a20c9

File tree

2 files changed

+36
-37
lines changed

2 files changed

+36
-37
lines changed

08_error.md

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,18 @@ Some languages want to know the types of all your bindings and expressions befor
9898

9999
Still, types provide a useful framework for talking about programs. A lot of mistakes come from being confused about the kind of value that goes into or comes out of a function. If you have that information written down, you're less likely to get confused.
100100

101-
You could add a comment like the following before the `goalOrientedRobot` function from the previous chapter to describe its type:
101+
You could add a comment like the following before the `findRoute` function from the previous chapter to describe its type:
102102

103103
```
104-
// (VillageState, Array) → {direction: string, memory: Array}
105-
function goalOrientedRobot(state, memory) {
104+
// (graph: Object, from: string, to: string) => string[]
105+
function findRoute(graph, from, to) {
106106
// ...
107107
}
108108
```
109109

110110
There are a number of different conventions for annotating JavaScript programs with types.
111111

112-
One thing about types is that they need to introduce their own complexity to be able to describe enough code to be useful. What do you think would be the type of the `randomPick` function that returns a random element from an array? You'd need to introduce a _((type variable))_, _T_, which can stand in for any type, so that you can give `randomPick` a type like `([T]) → T` (function from an array of *T*s to a *T*).
112+
One thing about types is that they need to introduce their own complexity to be able to describe enough code to be useful. What do you think would be the type of the `randomPick` function that returns a random element from an array? You'd need to introduce a _((type variable))_, _T_, which can stand in for any type, so that you can give `randomPick` a type like `(T[]) → T` (function from an array of *T*s to a *T*).
113113

114114
{{index "type checking", TypeScript}}
115115

@@ -217,7 +217,7 @@ _Right_. Dividing 13 by 10 does not produce a whole number. Instead of `n /= bas
217217

218218
{{index "JavaScript console", "debugger statement"}}
219219

220-
An alternative to using `console.log` to peek into the program's behavior is to use the _debugger_ capabilities of your browser. Browsers come with the ability to set a _((breakpoint))_ on a specific line of your code. When the execution of the program reaches a line with a breakpoint, it is paused, and you can inspect the values of bindings at that point. I won't go into details, as debuggers differ from browser to browser, but look in your browser's ((developer tools)) or search the Web for more information.
220+
An alternative to using `console.log` to peek into the program's behavior is to use the _debugger_ capabilities of your browser. Browsers come with the ability to set a _((breakpoint))_ on a specific line of your code. When the execution of the program reaches a line with a breakpoint, it is paused, and you can inspect the values of bindings at that point. I won't go into details, as debuggers differ from browser to browser, but look in your browser's ((developer tools)) or search the Web for instructions.
221221

222222
Another way to set a breakpoint is to include a `debugger` statement (consisting of simply that keyword) in your program. If the ((developer tools)) of your browser are active, the program will pause whenever it reaches such a statement.
223223

@@ -253,14 +253,14 @@ Now any code that calls `promptNumber` must check whether an actual number was r
253253

254254
{{index "error handling"}}
255255

256-
In many situations, mostly when ((error))s are common and the caller should be explicitly taking them into account, returning a special value is a good way to indicate an error. It does, however, have its downsides. First, what if the function can already return every possible kind of value? In such a function, you'll have to do something like wrap the result in an object to be able to distinguish success from failure.
256+
In many situations, mostly when ((error))s are common and the caller should be explicitly taking them into account, returning a special value is a good way to indicate an error. It does, however, have its downsides. First, what if the function can already return every possible kind of value? In such a function, you'll have to do something like wrap the result in an object to be able to distinguish success from failure, the way the `next` method on the iterator interface does.
257257

258258
```
259259
function lastElement(array) {
260260
if (array.length == 0) {
261261
return {failed: true};
262262
} else {
263-
return {element: array[array.length - 1]};
263+
return {value: array[array.length - 1]};
264264
}
265265
}
266266
```
@@ -273,7 +273,7 @@ The second issue with returning special values is that it can lead to awkward co
273273

274274
{{index "error handling"}}
275275

276-
When a function cannot proceed normally, what we would _like_ to do is just stop what we are doing and immediately jump to a place that knows how to handle the problem. This is what _((exception handling))_ does.
276+
When a function cannot proceed normally, what we would often _like_ to do is just stop what we are doing and immediately jump to a place that knows how to handle the problem. This is what _((exception handling))_ does.
277277

278278
{{index ["control flow", exceptions], "raising (exception)", "throw keyword", "call stack"}}
279279

@@ -344,7 +344,7 @@ const accounts = {
344344
345345
function getAccount() {
346346
let accountName = prompt("Enter an account name");
347-
if (!accounts.hasOwnProperty(accountName)) {
347+
if (!Object.hasOwn(accounts, accountName)) {
348348
throw new Error(`No such account: ${accountName}`);
349349
}
350350
return accountName;
@@ -363,7 +363,7 @@ But `transfer` _first_ removes the money from the account and _then_ calls `getA
363363

364364
That code could have been written a little more intelligently, for example by calling `getAccount` before it starts moving money around. But often problems like this occur in more subtle ways. Even functions that don't look like they will throw an exception might do so in exceptional circumstances or when they contain a programmer mistake.
365365

366-
One way to address this is to use fewer side effects. Again, a programming style that computes new values instead of changing existing data helps. If a piece of code stops running in the middle of creating a new value, no one ever sees the half-finished value, and there is no problem.
366+
One way to address this is to use fewer side effects. Again, a programming style that computes new values instead of changing existing data helps. If a piece of code stops running in the middle of creating a new value, no existing data structures were damaged, making it easier to recover.
367367

368368
{{index block, "try keyword", "finally keyword"}}
369369

@@ -516,9 +516,9 @@ I do not recommend trying to write assertions for every possible kind of bad inp
516516

517517
## Summary
518518

519-
Mistakes and bad input are facts of life. An important part of programming is finding, diagnosing, and fixing bugs. Problems can become easier to notice if you have an automated test suite or add assertions to your programs.
519+
An important part of programming is finding, diagnosing, and fixing bugs. Problems can become easier to notice if you have an automated test suite or add assertions to your programs.
520520

521-
Problems caused by factors outside the program's control should usually be handled gracefully. Sometimes, when the problem can be handled locally, special return values are a good way to track them. Otherwise, exceptions may be preferable.
521+
Problems caused by factors outside the program's control should usually be actively planned for. Sometimes, when the problem can be handled locally, special return values are a good way to track them. Otherwise, exceptions may be preferable.
522522

523523
Throwing an exception causes the call stack to be unwound until the next enclosing `try/catch` block or until the bottom of the stack. The exception value will be given to the `catch` block that catches it, which should verify that it is actually the expected kind of exception and then do something with it. To help address the unpredictable control flow caused by exceptions, `finally` blocks can be used to ensure that a piece of code _always_ runs when a block finishes.
524524

@@ -573,21 +573,22 @@ hint}}
573573
Consider the following (rather contrived) object:
574574

575575
```
576-
const box = {
577-
locked: true,
578-
unlock() { this.locked = false; },
579-
lock() { this.locked = true; },
580-
_content: [],
576+
const box = new class {
577+
locked = true;
578+
#content = [];
579+
580+
unlock() { this.locked = false; }
581+
lock() { this.locked = true; }
581582
get content() {
582583
if (this.locked) throw new Error("Locked!");
583-
return this._content;
584+
return this.#content;
584585
}
585586
};
586587
```
587588

588589
{{index "private property", "access control"}}
589590

590-
It is a ((box)) with a lock. There is an array in the box, but you can get at it only when the box is unlocked. Directly accessing the private `_content` property is forbidden.
591+
It is a ((box)) with a lock. There is an array in the box, but you can get at it only when the box is unlocked.
591592

592593
{{index "finally keyword", "exception handling"}}
593594

@@ -596,14 +597,15 @@ Write a function called `withBoxUnlocked` that takes a function value as argumen
596597
{{if interactive
597598

598599
```
599-
const box = {
600-
locked: true,
601-
unlock() { this.locked = false; },
602-
lock() { this.locked = true; },
603-
_content: [],
600+
const box = new class {
601+
locked = true;
602+
#content = [];
603+
604+
unlock() { this.locked = false; }
605+
lock() { this.locked = true; }
604606
get content() {
605607
if (this.locked) throw new Error("Locked!");
606-
return this._content;
608+
return this.#content;
607609
}
608610
};
609611

code/solutions/08_2_the_locked_box.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
1-
const box = {
2-
locked: true,
3-
unlock() { this.locked = false; },
4-
lock() { this.locked = true; },
5-
_content: [],
1+
const box = new class {
2+
locked = true;
3+
#content = [];
4+
5+
unlock() { this.locked = false; }
6+
lock() { this.locked = true; }
67
get content() {
78
if (this.locked) throw new Error("Locked!");
8-
return this._content;
9+
return this.#content;
910
}
1011
};
1112

1213
function withBoxUnlocked(body) {
1314
let locked = box.locked;
14-
if (!locked) {
15-
return body();
16-
}
17-
18-
box.unlock();
15+
if (locked) box.unlock();
1916
try {
2017
return body();
2118
} finally {
22-
box.lock();
19+
if (locked) box.lock();
2320
}
2421
}
2522

0 commit comments

Comments
 (0)