Last active
August 29, 2015 14:15
-
-
Save propensive/b0ec2a9a22e9fe9834de to your computer and use it in GitHub Desktop.
Using TMaps for error handling
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Welcome to Scala version 2.10.4 (OpenJDK 64-Bit Server VM, Java 1.6.0_27). | |
Type in expressions to have them evaluated. | |
Type :help for more information. | |
// Import the Rapture modules we need | |
scala> import rapture._, uri._, codec._, io._, fs._, core._, csv._ | |
import rapture._ | |
import uri._ | |
import codec._ | |
import io._ | |
import fs._ | |
import core._ | |
import csv._ | |
// Import some more configuration context | |
scala> import csvBackends.simple._, encodings.`UTF-8`._, platform.posix | |
import csvBackends.simple._ | |
import encodings.UTF$minus8._ | |
import platform.adaptive | |
// We use the `returnOutcome` mode which collects failures, without throwing; like a Scalaz Validation. | |
scala> import modes.returnOutcome._ | |
import modes.returnOutcome._ | |
// We attempt to parse the contents of a URI from a local file | |
scala> val csv = Csv.parse(uri"file:///home/jpretty/consts.csv") | |
csv: rapture.core.Outcome[rapture.csv.Csv,rapture.csv.CsvParseException] = | |
Result(Csv( | |
"ID","Name","Value" | |
"1","pi","3.14159" | |
"2","e","2.718" | |
)) | |
// We got a successful `Result`, as the CSV parsed successfully. Note that the return type includes a `CsvParseException`, | |
// indicating that this was a possible failure. | |
// As it was successful, we can get the `result` out of the `Outcome`. | |
scala> val csv2 = csv.result | |
csv2: rapture.csv.Csv = | |
Csv( | |
"ID","Name","Value" | |
"1","pi","3.14159" | |
"2","e","2.718" | |
) | |
// We will attempt to extract a `Const` from a row in the CSV file, so we define it as a case class. (Note that an implicit | |
// extractor for this type will be automatically generated by a macro) | |
scala> case class Const(id: Int, name: String, value: Double) | |
defined class Const | |
// Let's try to read the first line as a `Const`. | |
scala> val header = csv2.rows.head.as[Const] | |
header: rapture.core.Outcome[Const,rapture.csv.CsvGetException] = | |
Problems( | |
rapture.csv.CsvGetException | |
type mismatch: Could not read value of type integer in column 0 | |
type mismatch: Could not read value of type double in column 2 | |
) | |
// This failed because the first line contains headers, so we get a `Problems` type returned. Note that this encapsulates two | |
// separate problems. If using a different Rapture mode, then usually only the first exception would be reported. | |
// Note also that, unlike the first `Outcome`, this one is typed on `CsvGetException`. | |
// Now, let's try the same thing in a single line using for-comprehension style. This is allowed because `Outcome`s have | |
// `map` and `flatMap` defined on them. | |
scala> val c = for(csv <- Csv.parse(uri"file:///home/jpretty/consts.csv"); const <- csv.rows.head.as[Const]) yield const | |
c: rapture.core.Outcome[Const,rapture.csv.CsvParseException with rapture.csv.CsvGetException] = | |
Problems( | |
rapture.csv.CsvGetException: | |
type mismatch: Could not read value of type integer in column 0 | |
type mismatch: Could not read value of type double in column 2 | |
) | |
// As before, we get the same list of problems, but note that the `Outcome` type is now parameterized on `CsvParseException | |
// with CsvGetException`; either exception type could be responsible for the failure. | |
// Are there any `CsvParseException`s? No. | |
scala> c.problems[CsvParseException] | |
res0: Vector[rapture.csv.CsvParseException] = Vector() | |
// Are there any `CsvGetException`s? Yes! | |
scala> c.problems[CsvGetException] | |
res1: Vector[rapture.csv.CsvGetException] = Vector(rapture.csv.CsvTypeMismatch: type mismatch: Could not read value of type integer in column 0, rapture.csv.CsvTypeMismatch: type mismatch: Could not read value of type double in column 2) | |
// Are there any `NullPointerException`s? No - that doesn't even compile! | |
scala> c.problems[NullPointerException] | |
<console>:43: error: type arguments [NullPointerException] do not conform to method problems's type parameter bounds [E2 >: rapture.csv.CsvParseException with rapture.csv.CsvGetException] | |
c.problems[NullPointerException] | |
^ | |
// So, let's report the problems | |
scala> c.problems[CsvGetException].foreach { case CsvTypeMismatch(t, c) => println("Oh dear.") } | |
<console>:43: warning: match may not be exhaustive. | |
It would fail on the following inputs: CsvMissingValue(_) | |
c.problems[CsvGetException].foreach { case CsvTypeMismatch(t, c) => println("Oh dear.") } | |
^ | |
Oh dear. | |
Oh dear. | |
// This worked, but the compiler reported a warning. It turns out that CsvGetException is a sealed supertrait of two possible | |
// sorts of failure: `CsvTypeMismatch` and `CsvMissingValue`. To make the warning go away, we need to handle both cases: | |
scala> c.problems[CsvGetException].foreach { case CsvTypeMismatch(t, c) => println("Oh dear."); case CsvMissingValue(c) => "What?" } | |
Oh dear. | |
Oh dear. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment