|
| 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