How to refactor a function that throws exceptions? - scala

Suppose I am refactoring a function like this:
def check(ox: Option[Int]): Unit = ox match {
case None => throw new Exception("X is missing")
case Some(x) if x < 0 => throw new Exception("X is negative")
case _ => ()
}
I'd like to get rid of the exceptions but I need to keep the check signature and behavior as is, so I'm factoring out a pure implementation -- doCheck:
import scala.util.{Try, Success, Failure}
def doCheck(ox: Option[Int]): Try[Unit] = ???
def check(ox: Option[Int]): Unit = doCheck(ox).get
Now I am implementing doCheck as follows:
def doCheck(ox: Option[Int]): Try[Unit] = for {
x <- ox toTry MissingX()
_ <- (x > 0) toTry NegativeX(x)
} yield ()
Using the following implicits:
implicit class OptionTry[T](o: Option[T]) {
def toTry(e: Exception): Try[T] = o match {
case Some(t) => Success(t)
case None => Failure(e)
}
}
implicit class BoolTry(bool: Boolean) {
def toTry(e: Exception): Try[Unit] = if (bool) Success(Unit) else Failure(e)
}
The implicits certainly add more code. I hope to replace OptionTry with an implicit from scalaz/cats someday and maybe find an analog for BoolTry.

You could refactor with a loan pattern and Try.
def withChecked[T](i: Option[Int])(f: Int => T): Try[T] = i match {
case None => Failure(new java.util.NoSuchElementException())
case Some(p) if p >= 0 => Success(p).map(f)
case _ => Failure(
new IllegalArgumentException(s"negative integer: $i"))
}
Then it can be used as following.
val res1: Try[String] = withChecked(None)(_.toString)
// res1 == Failure(NoSuchElement)
val res2: Try[Int] = withChecked(Some(-1))(identity)
// res2 == Failure(IllegalArgumentException)
def foo(id: Int): MyType = ???
val res3: Try[MyType] = withChecked(Some(2)) { id => foo(id) }
// res3 == Success(MyType)

Related

Lazily traverse collection of functions short-circuiting on first success

The goal is to lazily evaluate a collection of functions stopping on and returning the first happy result. Computation should be sequential. Here is my attempt
def f1(i: Int): Either[String, Int] = {println(s"f1($i)"); Left("boom-f1") }
def f2(i: Int): Either[String, Int] = {println(s"f2($i)"); Left("boom-f2") }
def f3(i: Int): Either[String, Int] = {println(s"f3($i)"); Right(i) }
val in = 42
(f1(in) #:: f2(in) #:: f3(in) #:: Stream.empty) collectFirst { case Right(x) => x } toRight("boom")
which outputs
f1(42)
f2(42)
f3(42)
res0: Either[String,Int] = Right(42)
where we see all three executed, whilst
def f1(i: Int): Either[String, Int] = {println(s"f1($i)"); Right(i) }
def f2(i: Int): Either[String, Int] = {println(s"f2($i)"); Right(i) }
def f3(i: Int): Either[String, Int] = {println(s"f3($i)"); Right(i) }
would output
f1(42)
res0: Either[String,Int] = Right(42)
where we see only one executed.
Does cats provide abstraction for such lazy failure-biased traversal?
You can use the Ior data type which is an inclusive-or relationship between two data types.
import cats.data.Ior
import cats.implicits._
import scala.annotation.tailrec
object Main2 {
def main(args: Array[String]) : Unit = {
def f1(i: Int): Either[String, Int] = {println(s"f1($i)"); Left("boom-f1") }
def f2(i: Int): Either[String, Int] = {println(s"f2($i)"); Left("boom-f2") }
def f3(i: Int): Either[String, Int] = {println(s"f3($i)"); Right(i) }
def traverseLazy(input: Int, list: List[Int => Either[String, Int]]): Ior[List[String], Int] = {
#tailrec
def go(ls: List[Int => Either[String, Int]], acc: List[String]): Ior[List[String], Int] = ls match {
case x :: xs => x(input) match {
case Left(error) => go(xs, error :: acc)
case Right(value) => if (ls.isEmpty) value.rightIor else Ior.both(acc, value)
}
case Nil => acc.leftIor
}
go(list, List.empty)
}
val res = traverseLazy(42, List(f1, f2, f3)).fold(
_.intercalate("\n"),
res => s"succeeded with $res",
(errors, res) => s"completed successfully with res $res but some errors were also found: ${errors.intercalate(", ")}")
println(res)
}
}
Ah I was overcomplicating, orElse already implements such semantics and gives simply
f1(in) orElse f2(in) orElse f3(in) orElse Left("boom")
as it takes by-name parameter.

How to write it idiomatically in Scala?

Suppose I have a function to check a string:
case class MyError(msg: String)
val oops = MyError("oops")
def validate(s: String):Either[MyError, Unit] =
if (s == "a") Right(()) else Left(oops)
Now I would like to reuse it and write a new function to check the head of a list of strings and return either an error or the list tail.
// should be validateHeadOfList but I don't want to change the name now
def validateList(xs: List[String]): Either[MyError, List[String]] =
xs match {
case head::tail =>
validate(head).fold(err => Left(err), _ => Right(tail))
case _ => Left(oops)
}
This function works but doesn't look elegant. How would you improve it ?
Your implementation looks rather idiomatic to me, but if you're looking for a possibly more concise alternative - I think this does exactly the same, and is (arguably) more concise:
def validateList(xs: List[String]): Either[MyError, List[String]] =
xs.headOption.map(validate).map(_.right.map(_ => xs.tail)).getOrElse(Left(oops))
Assuming you actually want to return either a single error or the original list, then the following will work. I can't comment on whether this is idiomatic Scala though.
case class MyError(msg: String)
val oops = MyError("oops")
def validate(s: String): Either[MyError, Unit] =
if (s == "a") ().asRight else oops.asLeft
final def validateList(list: List[String]): Either[MyError, List[String]] = {
#scala.annotation.tailrec
def loop(xs: List[String]): Either[MyError, List[String]] = {
xs match {
case head :: tail =>
validate(head) match {
case Left(error) => error.asLeft
case _ => loop(tail)
}
case _ => list.asRight
}
}
loop(list)
}
For example:
scala> validateList(List("a", "a", "a"))
res0: Either[MyError,List[String]] = Right(List(a, a, a))
scala> validateList(List("a", "b", "a"))
res1: Either[MyError,List[String]] = Left(MyError(oops))

pattern matching on function parameters in scala

Is it possible to pattern match on function heads in scala?
For example, can I write something along the lines of:
def myFunction(a:: b:: xs): Int = ???
def myFunction(a:: xs): Int = ???
def myFunction(List.empty): Int = ???
You can use partial functions for this case. Example:
val myFunctionCase1: PartialFunction[List[Int], Int] = {
case a :: b :: xs => ???
}
val myFunctionCase2: PartialFunction[List[Int], Int] = {
case a :: xs => ???
}
val myFunctionCase3: PartialFunction[List[Int], Int] = {
case Nil => ???
}
// compose functions
val myFunction: List[Int] => Int =
myFunctionCase1 orElse myFunctionCase2 orElse myFunctionCase3
Usage examples:
myFunctionCase1(List(1,2,3)) // invoke
myFunctionCase1(List(1)) // throw MatchError
myFunctionCase2(List(1)) // invoke
...
myFunction(List(1,2,3))
myFunction(List(1))
myFunction(Nil)
...

How to match type parameter of a function in Scala

I would like to do something like this:
implicit class MyString(s: String) {
def getAs[T]: T = {
T match {
case q if q == classOf[Int] => s.toInt
case q if q == classOf[Boolean] => s.toBoolean
}
}
}
This doesn't compile, of course. How do I write this so it does?
Consider this approach:
object Parse {
def parse[T](f:String => Option[T]) = f
implicit val parseInt = parse(s => Try(s.toInt).toOption)
implicit val parseLong = parse(s => Try(s.toLong).toOption)
implicit val parseDouble = parse(s => Try(s.toDouble).toOption)
implicit val parseBoolean = parse(s => Try(s.toBoolean).toOption)
}
implicit class MyString(s:String) {
def getAs[T]()(implicit run: String => Option[T]): Option[T] = run(s)
}
Usage:
def main(args: Array[String]) {
import Parse._
"true".getAs[Boolean].foreach(println)
"12345".getAs[Int].foreach(println)
}
When use classOf for type match, there maybe will have some issues, example:
scala> classOf[List[Int]] == classOf[List[String]]
res17: Boolean = true
scala> typeOf[List[Int]] =:= typeOf[List[String]]
res18: Boolean = false
classOf only store the class information not with generics type
typeOf will store full type information
TypeTags and Manifests
class MyString(s: String) {
def getAs[T](implicit tag: TypeTag[T]): T = {
tag.tpe match {
case t if t =:= typeOf[Int] => s.toInt.asInstanceOf[T]
}
}
}
scala> new MyString("123")
res2: MyString = MyString#7fca02
scala> res6.getAs[Int]
res3: Int = 123
use TypeType tag to get type info, and call getAs with type information.
This is what I have come up with so far:
import reflect.runtime.universe.TypeTag
import scala.reflection.runtime.universe._
implicit class MyString(s: String) {
def getAs[T : TypeTag]: T = {
typeOf[T] match {
case t if t =:= typeOf[Int] => s.toInt.asInstanceOf[T]
case t if t =:= typeOf[Boolean] => s.toBoolean.asInstanceOf[T]
}
}
}
Running with this in REPL:
scala> "32".getAs[Int]
res25: Int = 32
scala> "32".getAs[Boolean]
java.lang.IllegalArgumentException: For input string: "32"
at scala.collection.immutable.StringLike$class.parseBoolean(StringLike.scala:290)
at scala.collection.immutable.StringLike$class.toBoolean(StringLike.scala:260)
at scala.collection.immutable.StringOps.toBoolean(StringOps.scala:30)
at MyString.getAs(<console>:33)
... 43 elided
scala> "false".getAs[Int]
java.lang.NumberFormatException: For input string: "false"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
at scala.collection.immutable.StringOps.toInt(StringOps.scala:30)
at MyString.getAs(<console>:32)
... 43 elided
scala> "false".getAs[Boolean]
res28: Boolean = false
scala> "false".getAs[String]
scala.MatchError: String (of class scala.reflect.internal.Types$AliasNoArgsTypeRef)
at MyString.getAs(<console>:31)
... 43 elided
Better, I think, would be to return an option[T], and catch any issues such as a type T that isn't catered for, or attempting a cast that will fail. I started mucking around with scala's Try (and its .toOption method), but hit some odd errors so haven't gotten any further with that.
EDIT: just using a simple try-catch, we can get:
implicit class MyString(s: String) {
def getAs[T : TypeTag]: Option[T] = try {
typeOf[T] match {
case t if t =:= typeOf[Int] => Some(s.toInt.asInstanceOf[T])
case t if t =:= typeOf[Boolean] => Some(s.toBoolean.asInstanceOf[T])
}
} catch {
case ex: Exception => None
}
}
Resulting in:
scala> "false".getAs[String]
res30: Option[String] = None
scala> "32".getAs[Boolean]
res31: Option[Boolean] = None
scala> "32".getAs[Int]
res32: Option[Int] = Some(32)
scala> "true".getAs[Boolean]
res33: Option[Boolean] = Some(true)
scala> "true".getAs[Int]
res34: Option[Int] = None
Based on the answers given by #chengpohi and #Shadowlands, this is what I came up with.
object ImplicitsStartingWithS {
implicit class MyString(s: String) {
val str = s.trim
import reflect.runtime.universe.TypeTag
import scala.reflect.runtime.universe._
def getAs[T](implicit tag: TypeTag[T]): Option[T] = {
val value = tag.tpe match {
case t if t =:= typeOf[Int] => str.toIntStr.map(_.toInt)
case t if t =:= typeOf[Long] => str.toIntStr.map(_.toLong)
case t if t =:= typeOf[Float] => str.toNumericStr.map(_.toFloat)
case t if t =:= typeOf[Double] => str.toNumericStr.map(_.toDouble)
case _ => None
}
value.asInstanceOf[Option[T]]
}
def toDecimalStr = "^-*\\d+\\.\\d+$".r.findFirstIn(s)
def toIntStr = "^-*\\d+$".r.findFirstIn(s)
def toNumericStr = {
s.toDecimalStr match {
case Some(decimalStr) => Some(decimalStr)
case None => s.toIntStr
}
}
}
}
This avoids exception handling for faster response.

Making Scala choose less specific overloaded method in presence of argument of type Nothing

If come across an interesting case with thunks versus functions in the presence of type Nothing:
object Test {
def apply(thunk: => Any ): String => Any = _ => thunk
def apply(fun: String => Any): String => Any = fun
}
val res0 = Test { println("hello") }
res0("foo") // --> hello
val res1 = Test { x: String => println(s"hello $x") }
res1("foo") // --> hello foo
val res2 = Test { x: String => throw new RuntimeException("ex") }
util.Try(res2("foo")) // --> Failure
val res3 = Test { throw new RuntimeException("ex") } // boom!
Now the tricky bit is the last case. Is it possible to modify the apply method to make Scala choose the thunk version of it, instead of the Function1 version (which is more specific and thus preferred, and Nothing <: Function1[_,_], therefore...)
I tried to come up with low-high priority implicits and magnet pattern, but haven't found a solution yet.
Here's a quick draft of a type-safe approach based on type classes:
object Test {
trait Wrap[A, B] { def apply(a: => A): String => B }
trait LowWrap {
implicit def thunkWrap[A] = new Wrap[A, A] { def apply(a: => A) = _ => a }
}
trait MidWrap extends LowWrap {
implicit def funcWrap[A] = new Wrap[String => A, A] {
def apply(f: => String => A) = f
}
}
object Wrap extends MidWrap {
implicit object nothingWrap extends Wrap[Nothing, Nothing] {
def apply(f: => Nothing) = _ => f
}
}
def apply[A, B](a: => A)(implicit w: Wrap[A, B]) = w(a)
}
And then:
scala> Test { println("hello") }
res0: String => Unit = <function1>
scala> res0("foo")
hello
scala> Test { x: String => println(s"hello $x") }
res2: String => Unit = <function1>
scala> res2("foo")
hello foo
scala> Test { x: String => throw new RuntimeException("ex") }
res4: String => Nothing = <function1>
scala> util.Try(res4("foo"))
res5: scala.util.Try[Nothing] = Failure(java.lang.RuntimeException: ex)
scala> Test { throw new RuntimeException("ex") }
res6: String => Nothing = <function1>
scala> util.Try(res6("foo"))
res7: scala.util.Try[Nothing] = Failure(java.lang.RuntimeException: ex)
You might be able to simplify a bit, add variance, etc.
Use:
val res3 = Test { (throw new RuntimeException("ex")): Any }
This works as expected. (No exception on creation, exception when calling res3).
A solution which uses reflection. (Still curious: can one write a static solution?)
import reflect.runtime.universe._
object Test {
def apply[A: TypeTag](thunk: => A): String => Any =
if (typeOf[A] =:= typeOf[Nothing]) // hah, caught you
_ => thunk
else if (typeOf[A] <:< typeOf[String => Any])
thunk.asInstanceOf[String => Any]
else
_ => thunk
}
val res0 = Test { println("hello") }
res0("foo") // --> hello
val res1 = Test { x: String => println(s"hello $x") }
res1("foo") // --> hello foo
val res2 = Test { x: String => throw new RuntimeException("ex") }
util.Try(res2("foo")) // --> Failure
val res3 = Test { throw new RuntimeException("ex") }
util.Try(res3("foo")) // --> Failure
(a macro based version of this would be static, I guess)