Skip to content

Commit 0812c6e

Browse files
committed
Continue expanding the outline
1 parent a029497 commit 0812c6e

File tree

1 file changed

+96
-62
lines changed

1 file changed

+96
-62
lines changed

TSPL.docc/LanguageGuide/ErrorHandling.md

Lines changed: 96 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,8 @@ can be values of any type that conforms to the `Error` protocol.
707707
This approach matches the reality that
708708
you don't know ahead of time every error that could happen
709709
while the code is running,
710-
especially when propagating errors thrown by code you didn't write.
710+
especially when propagating errors thrown somewhere else.
711+
This approach also reflects the fact that errors can change over time.
711712
New versions of a library can throw new errors ---
712713
including libraries used by your dependencies ---
713714
and the rich complexity of real-world user configurations
@@ -716,21 +717,48 @@ The error handling code in the examples above
716717
always includes a default case to handle errors
717718
that don't have their own specific `catch` clause.
718719

719-
However,
720-
some code throws error of only a specific type,
721-
so it's useful to specify that type.
720+
In some special cases,
721+
you might write code that's specific about what error it throws:
722722

723-
- When you encapsulate errors within some unit of code,
724-
like a library,
725-
if using a specific error type is useful for you.
726-
In this case,
727-
the library always handles all of its own errors.
728-
This kind of error is an implementation detail of the library.
729-
730-
- When targeting an embedded system
723+
- When running code on an embedded system
731724
where dynamic allocation of memory isn't possible.
732-
Swift needs to allocate memory at run time
733-
when throwing an instance `any Error` or other boxed protocol types.
725+
Throwing an instance `any Error` or another boxed protocol type
726+
requires allocating memory at run time to store the error.
727+
Throwing an error of a specific type instead
728+
lets Swift allocate that memory upfront.
729+
730+
- When the errors are an implementation detail of a library,
731+
or some other unit of code,
732+
and aren't part of the interface to that code.
733+
Because only the library's code throws errors ---
734+
it doesn't propagate errors from other code ---
735+
you can make an exhaustive list of all possible failures.
736+
And because the library always handles its own errors,
737+
738+
739+
Because all of these errors are thrown within the library's code,
740+
and they're always handled within that library.
741+
Because
742+
Because the library's clients never see the errors,
743+
◊ the API surface expressively limitations don't matter
744+
745+
-
746+
* In code that only rethrows errors,
747+
especially when the throwing code comes from a closure the caller provided.
748+
(However, neither rethrows nor typed throws is a strict superset of the other.)
749+
Example: `map` in the stdlib.
750+
Xref to reference section -- this chapter doesn't discuss rethrows
751+
752+
753+
In most code,
754+
you don't specify the type for the errors it throws,
755+
implicitly throwing an error of type `any Error`
756+
However,
757+
Swift also supports
758+
some code only throws errors of a specific type.
759+
in some places your code only throws
760+
you might need to write code that throws errors of only a specific type,
761+
so it's useful to specify that type.
734762

735763
- When you throw errors from code that
736764
doesn't depend on any other throwing code,
@@ -754,9 +782,10 @@ enum StatisticsError: Error {
754782
```
755783

756784
To specify that a function throws only `StatisticsError`
757-
you write `throws(StatisticsError)` when declaring the function.
758-
Because you write a type after `throws`
759-
this syntax is also called *typed throws*.
785+
you write `throws(StatisticsError)` when declaring the function,
786+
instead of just writing `throws`.
787+
This syntax is also called *typed throws*
788+
because you write the error type after `throws` --- for example:
760789

761790
```swift
762791
func summarize(_ ratings: [Int]) throws(StatisticsError) {
@@ -768,69 +797,82 @@ func summarize(_ ratings: [Int]) throws(StatisticsError) {
768797
counts[rating]! += 1
769798
}
770799

771-
print("One star:", counts[1]!)
772-
print("Two stars:", counts[2]!)
773-
print("Three stars:", counts[3]!)
774-
775800
print("*", counts[1]!, "-- **", counts[2]!, "-- ***", counts[3]!)
776801
}
777802
```
778803

779-
<!-- XXX pick one flavor of summary above -->
804+
In the code above,
805+
the `summarize(_:)` function summarizes a list of ratings
806+
expressed on a scale of 1 to 3.
807+
This function throws an instance of `StatisticsError` if the input isn't valid.
808+
809+
You can use the shorthand notation `throw .noRatings`
810+
instead of writing `throw StatisticsError.noRatings`
811+
because the function's error type is already defined.
812+
813+
814+
◊ throws(StatisticsError) is a subtype of throws(any Error)
815+
◊ so you can write `try summarize(...)` in a plain `throwing` context too
816+
- Most code that throws errors just writes `throws`.
817+
This is the same as writing `throws(any Error)`.
818+
However, you can write `throws(SomeErrorType)`
819+
to throw errors of a specific concrete type.
820+
780821

781-
When you write a specific error type,
782-
Swift checks at compile time that you don't throw any other errors.
783822

823+
When you write a specific error type,
824+
Swift checks that you don't throw any other errors.
825+
For example,
826+
if you tried to use `VendingMachineError` from examples earlier in this chapter
827+
in the `summarize(_:)` function above,
828+
that code would produce an error at compile time.
784829

830+
◊ rewrite
785831
Code that throws a single specific error type
786-
doesn't include the default `catch` clause ---
832+
doesn't need to include the default `catch` clause ---
787833
instead, Swift verifies that every possible error value
788834
has a corresponding `catch` clause.
789835

836+
837+
838+
839+
In addition to specifying the error type for a function,
840+
you can also write a specific error type
841+
in a `do`-`catch` block.
842+
For example:
843+
790844
```swift
791-
func printSummary(_ ratings: [Int]) {
792-
do throws(StatisticsError) {
793-
try summarize(ratings)
794-
} catch {
795-
switch error {
796-
case .noRatings:
797-
print("No ratings available")
798-
case .invalidRating(let rating):
799-
print("Invalid rating: \(rating)")
800-
}
845+
let ratings = [1, 2, 3, 2, 2, 1]
846+
do throws(StatisticsError) {
847+
try summarize(ratings)
848+
} catch {
849+
switch error {
850+
case .noRatings:
851+
print("No ratings available")
852+
case .invalidRating(let rating):
853+
print("Invalid rating: \(rating)")
801854
}
802855
}
856+
// Prints XXX
803857
```
804858

805-
## XXX OUTLINE XXX
859+
In this code, XXX
806860

807-
- Most code that throws errors just writes `throws`.
808-
This is the same as writing `throws(any Error)`.
809-
However, you can write `throws(SomeErrorType)`
810-
to throw errors of a specific concrete type.
811861

812-
- In contrast, a concrete error type is useful in some special circumstances:
862+
XXX
863+
If a function or `do` block throws only errors of a single type,
864+
the compiler infers that as the concrete error type.
865+
You can explicitly write `throws(any Error)` to suppress that.
813866

814-
* In code that only rethrows errors,
815-
especially when the throwing code comes from a closure the caller provided.
816-
(However, neither rethrows nor typed throws is a strict superset of the other.)
817-
Example: `map` in the stdlib.
818-
Xref to reference section -- this chapter doesn't discuss rethrows
867+
868+
## XXX OUTLINE XXX
819869

820870
- You can also use opaque types like `throws(some MyErrorProtocol)` --
821871
this is still "concrete" in sense that
822872
the errors are all instances of the concrete type
823873
that's hidden behind the opaque type.
824874
And there's still one specific error type.
825875

826-
- To specify the error type for a `do` block or a throwing function,
827-
write `throws(E)` where `E` is an error type.
828-
For example -- insert `summarize` from RUNNING EXAMPLE below.
829-
830-
- If a function or `do` block throws only errors of a single type,
831-
the compiler infers that as the concrete error type.
832-
You can explicitly write `throws(any Error)` to suppress that.
833-
834876
- For a normal error (of boxed protocol type)
835877
the `catch` clause needs to either include a general catch/default
836878
that handles errors whose types the other clauses don't handle,
@@ -839,14 +881,6 @@ func printSummary(_ ratings: [Int]) {
839881
without a default clause
840882
by handling just that specific error type.
841883

842-
XXX RUNNING EXAMPLE XXX
843-
844-
```swift
845-
printSummary([1, 2, 3, 2, 2, 1])
846-
printSummary([])
847-
printSummary([1, 100])
848-
```
849-
850884
## Specifying Cleanup Actions
851885

852886
You use a `defer` statement to execute a set of statements

0 commit comments

Comments
 (0)