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: docs/docs/reference/experimental/canthrow.md
+28-14Lines changed: 28 additions & 14 deletions
Original file line number
Diff line number
Diff line change
@@ -47,9 +47,9 @@ However, a programming language is not a framework; it has to cater also for tho
47
47
Why does `map` work so poorly with Java's checked exception model? It's because
48
48
`map`'s signature limits function arguments to not throw checked exceptions. We could try to come up with a more polymorphic formulation of `map`. For instance, it could look like this:
49
49
```scala
50
-
defmap[B, E](f: A=>BcanThrowE):List[B] canThrowE
50
+
defmap[B, E](f: A=>BthrowsE):List[B] throwsE
51
51
```
52
-
This assumes a type `A canThrow E` to indicate computations of type `A` that can throw an exception of type `E`. But in practice the overhead of the additional type parameters makes this approach unappealing as well. Note in particular that we'd have to parameterize _every method_ that takes a function argument that way, so the added overhead of declaring all these exception types looks just like a sort of ceremony we would like to avoid.
52
+
This assumes a type `A throws E` to indicate computations of type `A` that can throw an exception of type `E`. But in practice the overhead of the additional type parameters makes this approach unappealing as well. Note in particular that we'd have to parameterize _every method_ that takes a function argument that way, so the added overhead of declaring all these exception types looks just like a sort of ceremony we would like to avoid.
53
53
54
54
But there is a way to avoid the ceremony. Instead of concentrating on possible _effects_ such as "this code might throw an exception", concentrate on _capabilities_ such as "this code needs the capability to throw an exception". From a standpoint of expressiveness this is quite similar. But capabilities can be expressed as parameters whereas traditionally effects are expressed as some addition to result values. It turns out that this can make a big difference!
55
55
@@ -71,19 +71,32 @@ How can the ability be produced? There are several possibilities:
71
71
Most often, the ability is produced by having a using clause `(using CanThrow[Exc])` in some enclosing scope. This roughly corresponds to a `throws` clause
72
72
in Java. The analogy is even stronger since alongside `CanThrow` there is also the following type alias defined in the `scala` package:
That is, `R canThrow E` is a context function type that takes an implicit `CanThrow[E]` parameter and that returns a value of type `R`. Therefore, a method written like this:
76
+
That is, `R $throws E` is a context function type that takes an implicit `CanThrow[E]` parameter and that returns a value of type `R`. What's more, the compiler
77
+
will translate an infix types with `throws` as the operator to `$throws` applications
78
+
according to the rules
79
+
```
80
+
A throws E --> A $throws E
81
+
A throws E₁ | ... | Eᵢ --> A $throws E₁ ... $throws Eᵢ
82
+
```
83
+
Therefore, a method written like this:
77
84
```scala
78
85
defm(x: T)(usingCanThrow[E]):U
79
86
```
80
87
can alternatively be expressed like this:
81
88
```scala
82
-
defm(x: T):UcanThrowE
89
+
defm(x: T):UthrowsE
83
90
```
84
-
_Aside_: If we rename `canThrow` to `throws` we would have a perfect analogy with Java but unfortunately `throws` is already taken in Scala 2.13.
85
-
86
-
The `CanThrow`/`canThrow` combo essentially propagates the `CanThrow` requirement outwards. But where are these abilities created in the first place? That's in the `try` expression. Given a `try` like this:
91
+
Multiple `CanThrow` capabilities can be combined in a single throws clause. For instance, the method
92
+
```scala
93
+
defm2(x: T)(usingCanThrow[E1], CanThrow[E2]):U
94
+
```
95
+
can alternatively be expressed like this:
96
+
```scala
97
+
defm(x: T):U throws E1|E2
98
+
```
99
+
The `CanThrow`/`throws` combo essentially propagates the `CanThrow` requirement outwards. But where are these abilities created in the first place? That's in the `try` expression. Given a `try` like this:
87
100
88
101
```scala
89
102
try
@@ -126,16 +139,16 @@ You'll get this error message:
126
139
|The ability to throw exception LimitExceeded is missing.
127
140
|The ability can be provided by one of the following:
128
141
| - A using clause `(using CanThrow[LimitExceeded])`
129
-
| - A `canThrow` clause in a result type such as `X canThrow LimitExceeded`
142
+
| - A `throws` clause in a result type such as `X throws LimitExceeded`
130
143
| - an enclosing `try` that catches LimitExceeded
131
144
|
132
145
|The following import might fix the problem:
133
146
|
134
147
| import unsafeExceptions.canThrowAny
135
148
```
136
-
As the error message implies, you have to declare that `f` needs the ability to throw a `LimitExceeded` exception. The most concise way to do so is to add a `canThrow` clause:
149
+
As the error message implies, you have to declare that `f` needs the ability to throw a `LimitExceeded` exception. The most concise way to do so is to add a `throws` clause:
137
150
```scala
138
-
deff(x: Double):DoublecanThrowLimitExceeded=
151
+
deff(x: Double):DoublethrowsLimitExceeded=
139
152
if x < limit then x * x elsethrowLimitExceeded()
140
153
```
141
154
Now put a call to `f` in a `try` that catches `LimitExceeded`:
@@ -169,12 +182,12 @@ So the takeaway is that the effects as abilities model naturally provides for ef
169
182
170
183
## Gradual Typing Via Imports
171
184
172
-
Another advantage is that the model allows a gradual migration from current unchecked exceptions to safer exceptions. Imagine for a moment that `experimental.saferExceptions` is turned on everywhere. There would be lots of code that breaks since functions have not yet been properly annotated with `canThrow`. But it's easy to create an escape hatch that lets us ignore the breakages for a while: simply add the import
185
+
Another advantage is that the model allows a gradual migration from current unchecked exceptions to safer exceptions. Imagine for a moment that `experimental.saferExceptions` is turned on everywhere. There would be lots of code that breaks since functions have not yet been properly annotated with `throws`. But it's easy to create an escape hatch that lets us ignore the breakages for a while: simply add the import
173
186
```scala
174
187
importscala.unsafeExceptions.canThrowAny
175
188
```
176
189
This will provide the `CanThrow` ability for any exception, and thereby allow
177
-
all throws and all other calls, no matter what the current state of `canThrow` declarations is. Here's the
190
+
all throws and all other calls, no matter what the current state of `throws` declarations is. Here's the
178
191
definition of `canThrowAny`:
179
192
```scala
180
193
packagescala
@@ -188,7 +201,8 @@ enable more fluid explorations of code without regard for complete exception saf
188
201
189
202
To summarize, the extension for safer exception checking consists of the following elements:
190
203
191
-
- It adds to the standard library the class `scala.CanThrow`, the type `scala.canThrow`, and the `scala.unsafeExceptions` object, as they were described above.
204
+
- It adds to the standard library the class `scala.CanThrow`, the type `scala.$throws`, and the `scala.unsafeExceptions` object, as they were described above.
205
+
- It adds some desugaring rules ro rewrite `throws` types to cascaded `$throws` types.
192
206
- It augments the type checking of `throw` by _demanding_ a `CanThrow` ability or the thrown exception.
193
207
- It augments the type checking of `try` by _providing_`CanThrow` abilities for every caught exception.
Copy file name to clipboardExpand all lines: docs/docs/reference/soft-modifier.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@ title: Soft Keywords
5
5
6
6
A soft modifier is one of the identifiers `opaque`, `inline`, `open`, `transparent`, and `infix`.
7
7
8
-
A soft keyword is a soft modifier, or one of `derives`, `end`, `extension`, `using`, `|`, `+`, `-`, `*`
8
+
A soft keyword is a soft modifier, or one of `derives`, `end`, `extension`, `throws`, `using`, `|`, `+`, `-`, `*`
9
9
10
10
A soft modifier is treated as potential modifier of a definition if it is followed by a hard modifier or a keyword combination starting a definition (`def`, `val`, `var`, `type`, `given`, `class`, `trait`, `object`, `enum`, `case class`, `case object`). Between the two words there may be a sequence of newline tokens and soft modifiers.
* a given of class `CanThrow[Ex]` to be available.
8
8
*/
9
9
@experimental
10
-
@implicitNotFound("The ability to throw exception ${E} is missing.\nThe ability can be provided by one of the following:\n - A using clause `(using CanThrow[${E}])`\n - A `canThrow` clause in a result type such as `X canThrow ${E}`\n - an enclosing `try` that catches ${E}")
10
+
@implicitNotFound("The ability to throw exception ${E} is missing.\nThe ability can be provided by one of the following:\n - A using clause `(using CanThrow[${E}])`\n - A `throws` clause in a result type such as `X throws ${E}`\n - an enclosing `try` that catches ${E}")
@implicitNotFound("The capability to throw exception ${E} is missing.\nThe capability can be provided by one of the following:\n - A using clause `(using CanThrow[${E}])`\n - A throws clause in a result type such as `X throws ${E}`\n - an enclosing `try` that catches ${E}")
5
+
@implicitNotFound("The capability to throw exception ${E} is missing.\nThe capability can be provided by one of the following:\n - A using clause `(using CanThrow[${E}])`\n - A raises clause in a result type such as `X raises ${E}`\n - an enclosing `try` that catches ${E}")
0 commit comments