Skip to content

Instantly share code, notes, and snippets.

@propensive
Last active August 29, 2015 14:15
Show Gist options
  • Save propensive/b0ec2a9a22e9fe9834de to your computer and use it in GitHub Desktop.
Save propensive/b0ec2a9a22e9fe9834de to your computer and use it in GitHub Desktop.
Using TMaps for error handling
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