You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 08_error.md
+27-25Lines changed: 27 additions & 25 deletions
Original file line number
Diff line number
Diff line change
@@ -98,18 +98,18 @@ Some languages want to know the types of all your bindings and expressions befor
98
98
99
99
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.
100
100
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:
// (graph: Object, from: string, to: string) => string[]
105
+
function findRoute(graph, from, to) {
106
106
// ...
107
107
}
108
108
```
109
109
110
110
There are a number of different conventions for annotating JavaScript programs with types.
111
111
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*).
113
113
114
114
{{index "type checking", TypeScript}}
115
115
@@ -217,7 +217,7 @@ _Right_. Dividing 13 by 10 does not produce a whole number. Instead of `n /= bas
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.
221
221
222
222
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.
223
223
@@ -253,14 +253,14 @@ Now any code that calls `promptNumber` must check whether an actual number was r
253
253
254
254
{{index "error handling"}}
255
255
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.
257
257
258
258
```
259
259
function lastElement(array) {
260
260
if (array.length == 0) {
261
261
return {failed: true};
262
262
} else {
263
-
return {element: array[array.length - 1]};
263
+
return {value: array[array.length - 1]};
264
264
}
265
265
}
266
266
```
@@ -273,7 +273,7 @@ The second issue with returning special values is that it can lead to awkward co
273
273
274
274
{{index "error handling"}}
275
275
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.
let accountName = prompt("Enter an account name");
347
-
if (!accounts.hasOwnProperty(accountName)) {
347
+
if (!Object.hasOwn(accounts, accountName)) {
348
348
throw new Error(`No such account: ${accountName}`);
349
349
}
350
350
return accountName;
@@ -363,7 +363,7 @@ But `transfer` _first_ removes the money from the account and _then_ calls `getA
363
363
364
364
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.
365
365
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.
367
367
368
368
{{index block, "try keyword", "finally keyword"}}
369
369
@@ -516,9 +516,9 @@ I do not recommend trying to write assertions for every possible kind of bad inp
516
516
517
517
## Summary
518
518
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.
520
520
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.
522
522
523
523
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.
524
524
@@ -573,21 +573,22 @@ hint}}
573
573
Consider the following (rather contrived) object:
574
574
575
575
```
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; }
581
582
get content() {
582
583
if (this.locked) throw new Error("Locked!");
583
-
return this._content;
584
+
return this.#content;
584
585
}
585
586
};
586
587
```
587
588
588
589
{{index "private property", "access control"}}
589
590
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.
591
592
592
593
{{index "finally keyword", "exception handling"}}
593
594
@@ -596,14 +597,15 @@ Write a function called `withBoxUnlocked` that takes a function value as argumen
0 commit comments