Skip to content

Commit 70b6bf9

Browse files
author
Dean Wampler
committed
Examples of the new experimental "safer exceptions".
1 parent af04b80 commit 70b6bf9

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// src/main/scala/progscala3/rounding/saferexceptions/SaferExceptions.scala
2+
// This example is not in the book. It discusses new work, experimental in
3+
// Scala 3.1, to incorporate exception throwing into the type system, but without
4+
// some of the drawbacks of Java-style checked exceptions.
5+
package progscala3.rounding.saferexceptions
6+
import java.io.{IOException, File}
7+
import scala.annotation.experimental
8+
// Enable safer exceptions
9+
import language.experimental.saferExceptions
10+
// If you enable safer exceptions, use the following annotation as a transition
11+
// feature to allow exceptions to be thrown even when the handler logic isn't in
12+
// place for all cases. Remove this import when handlers have been added!
13+
// import unsafeExceptions.canThrowAny
14+
15+
/**
16+
* Usage: scala rounding.saferexceptions.SaferExceptions file1 [file2 ...]
17+
* Note that an object is used, not a `@def main`, because the compiler tells us
18+
* we need to annotate the SaferExceptions type with `@experimental` and this
19+
* appears to be the only way to do it. (Also, any methods outside the type that
20+
* use this feature would also need this annotation.)
21+
*
22+
* Here is the output:
23+
* ```
24+
* sbt:programming-scala-3rd-ed-code-examples> runMain progscala3.rounding.saferexceptions.SaferExceptions build.sbt badfile
25+
* [info] compiling 1 Scala source to .../target/scala-3.1.1-RC2/classes ...
26+
* [info] running (fork) progscala3.rounding.saferexceptions.SaferExceptions build.sbt badfile
27+
* [info] file build.sbt (.../build.sbt) has 4434 bytes.
28+
* [info] file badfile: IOException caught: badfile doesn't exist!
29+
* [success] Total time: 1 s, completed Jan 16, 2022, 12:20:48 PM
30+
* ```
31+
*/
32+
@experimental // Must annotate all the types or methods that use the feature...
33+
object SaferExceptions:
34+
def main(fileNames: Array[String]): Unit =
35+
fileNames.foreach { fileName =>
36+
try
37+
val file = openExistingFile(fileName)
38+
val path = file.getCanonicalPath()
39+
val size = file.length()
40+
println(s"file $fileName ($path) has $size bytes.")
41+
catch
42+
case ioe: IOException => println(s"file $fileName: IOException caught: ${ioe.getMessage}")
43+
}
44+
45+
def openExistingFile(fileName: String): File throws IOException =
46+
val file = new File(fileName)
47+
if file.exists() == false then throw new IOException(s"$fileName doesn't exist!")
48+
file
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// src/main/scala/progscala3/rounding/saferexceptions/SaferExceptionsNested.scala
2+
// This example is not in the book. It discusses new work, experimental in
3+
// Scala 3.1, to incorporate exception throwing into the type system, but without
4+
// the drawbacks of Java-style checked exceptions.
5+
package progscala3.rounding.saferexceptions
6+
import java.io.{IOException, File}
7+
import scala.annotation.experimental
8+
// Enable safer exceptions
9+
import language.experimental.saferExceptions
10+
// If you enable safer exceptions, use the following annotation as a transition
11+
// feature to allow exceptions to be thrown even when the handler logic isn't in
12+
// place for all cases. Remove this import when handlers have been added!
13+
// import unsafeExceptions.canThrowAny
14+
15+
/**
16+
* Usage: scala rounding.saferexceptions.SaferExceptionsNested file1 [file2 ...]
17+
* Note that an object is used, not a `@def main`, because the compiler tells us
18+
* we need to annotate the SaferExceptions type with `@experimental` and this
19+
* appears to be the only way to do it. (Also, any methods outside the type that
20+
* use this feature would also need this annotation.)
21+
*
22+
* Here is the output:
23+
* ```
24+
* sbt:programming-scala-3rd-ed-code-examples> runMain progscala3.rounding.saferexceptions.SaferExceptionsNested build.sbt badfile
25+
* [info] compiling 2 Scala sources to .../target/scala-3.1.1-RC2/classes ...
26+
* [info] running (fork) progscala3.rounding.saferexceptions.SaferExceptionsNested build.sbt badfile
27+
* [info] file build.sbt (.../build.sbt) has 4434 bytes.
28+
* [info] file badfile: IOException caught: badfile doesn't exist!
29+
* [success] Total time: 1 s, completed Jan 16, 2022, 12:32:51 PM
30+
* ```
31+
*/
32+
@experimental // Must annotate all the types or methods that use the feature...
33+
object SaferExceptionsNested:
34+
def main(fileNames: Array[String]): Unit =
35+
fileNames.foreach { fileName =>
36+
try
37+
val file = wrapper(fileName)
38+
val path = file.getCanonicalPath()
39+
val size = file.length()
40+
println(s"file $fileName ($path) has $size bytes.")
41+
catch
42+
case ioe: IOException => println(s"file $fileName: IOException caught: ${ioe.getMessage}")
43+
}
44+
45+
def wrapper(fileName: String): File throws IOException = openExistingFile(fileName)
46+
47+
/**
48+
* `File throws IOException` is equivalent to this definition of `openExisting`:
49+
* `def openExistingFile(fileName: String)(using CanThrow[IOException]) = ...
50+
*/
51+
def openExistingFile(fileName: String): File throws IOException =
52+
val file = new File(fileName)
53+
if file.exists() == false then throw new IOException(s"$fileName doesn't exist!")
54+
file

0 commit comments

Comments
 (0)