How to Right and Left from a Future - scala

I have a function as follows:
def bar(x : Int) : Either[String, Future[Option[Foo]]] = {
Goo() recover { case e => Left("Some error string") }
}
As you can see, if the Future fails then it will hit the partial function inside the recover body. This will return Left and satisfies the left part of the Either type. What I am stuck on is how to return the Right if the Goo future completes successfully.
I tried the following:
def bar(x : Int) : Either[String, Future[Option[Foo]]] = {
Goo().map(x => Right(Future.successful(x))) recover { case e => Left("Some error string") }
}
However, I get a type error indicating that the return type for bar is Future[Either[String, Future[Foo]]].
How can I return a Right(x) where x is some value of type Foo?
UPDATE
def bar(x : Int) : Future[Either[String, Option[Foo]]] = {
Goo().map(x => Right(x)) recover { case e => Left("Some error string") }
}

You didn't define Goo, but i'll assume for the moment the following:
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
case class Foo(n: Int)
/** Takes a string and returns a future int-parsing of it */
def Goo(s: String): Future[Foo] = Future {
Foo(java.lang.Integer.parseInt(s)) // will throw an exception on non-int
}
Then if you want bar(s: String) to return Either[String, Option[Foo]] where the Option is a Some[Foo] if the number is parseable and positive, or None if parseable but non-positive and the String is an explanation of why it failed to parse, you could do:
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import scala.util.control.NonFatal
def bar(s: String): Future[Either[String, Option[Foo]]] = {
Goo(s).map { foo: Foo =>
Right(if (foo.n > 0) Some(foo) else None)
}.recover {
case NonFatal(e) => Left("Failed to parse %s: %s".format(s, e))
}
}
voila:
scala> Await.result(bar("4"), Duration.Inf)
res1: Either[String,Option[Foo]] = Right(Some(Foo(4)))
scala> Await.result(bar("-4"), Duration.Inf)
res2: Either[String,Option[Foo]] = Right(None)
scala> Await.result(bar("four"), Duration.Inf)
res3: Either[String,Option[Foo]] = Left(Failed to parse four: java.lang.NumberFormatException: For input string: "four")

Related

How to get Left from a method that returns Future?

def myMethod(myType: String) :Future[Future[Either[List[MyError], MyClass]]] {
for {
first <- runWithSeq(firstSource)
}
yield {
runWithSeq(secondSource)
.map {s ->
val mine = MyClass(s.head, lars)
val errors = myType match {
case "all" => Something.someMethod(mine)
}
(s, errors)
}
.map { x =>
x._2.leftMap(xs => {
addInfo(x._1.head, xs.toList)
}).toEither
}
}
}
for {
myStuff <- myMethod("something")
} yield {
myStuff.collect {
case(Left(errors), rowNumber) =>
MyCaseClass(errors, None) //compilation error here
}
}
I get compilation error on MyCaseClass that expected: List[MyError], found: Any
The signature of MyCaseClass is:
case class MyCaseClass(myErrors: List[ValidationError])
How can I fix this such that I can correctly call MyCaseClass inside the yield?
Your code example doesn't make much sense, and doesn't compile, but if runWithSeq() returns a Future then you should be able to eliminate the double Future return type like so.
for {
_ <- runWithSeq(firstSource)
scnd <- runWithSeq(secondSource)
} yield { ...
Your example is pretty hard to paste and fix
Abstact example for this
Class C may be whatever you want
def test(testval: Int)(implicit ec: ExecutionContext): Future[Future[Either[String, Int]]] = {
Future(Future{
if (testval % 2 == 0) Right(testval) else Left("Smth wrong")
})
}
implicit class FutureEitherExt[A, B](ft: Future[Either[A, B]]) {
def EitherMatch[C](f1: A => C, f2: B => C)(implicit ec: ExecutionContext): Future[C] = {
ft.map {
case Left(value) => f1(value)
case Right(value) => f2(value)
}
}
}
val fl: Future[Either[String, Int]] = test(5).flatten
val result: Future[String] = fl.EitherMatch(identity, _.toString)

Generic String interpolator using StringContext

I'm trying to create some simple custom String interpolator, and I'm successful as long as I don't try to use a type parameter.
import scala.concurrent.Future
object StringImplicits {
implicit class FailureStringContext (val sc : StringContext) extends AnyVal {
// This WORKS, but it's specific to Future :(
def fail[T](args : Any*): Future[T] = {
val orig = sc.s (args : _*)
Future.exception[T](new Exception(orig))
}
// I want this to work for Option,Try,Future!!
def fail[M,T](args:Any*): M[T] = {
val orig = sc.s (args : _*)
// Obviously does not work..
M match {
case Future => Future.exception(new Exception(orig))
case Option => None
case Try => Failure(new Exception(orig))
case _ => ???
}
}
}
}
Can I get this to work? I can't use parametric polymorphism because I'm not the one defining those three types.
What's the equivalent in the type level for that pseudo-code pattern match?
LATEST ATTEMPT
My latest attempt was to use implicitly, but I don't have such implicit! I'd be actually interested to grab a hold of the type that the compiler wants me to return according to type inference.
def fail[T, M[T]](args:Any*): M[T] = {
val orig = sc.s(args: _*)
implicitly[M[T]] match {
case _:Future[T] => Future.exception(new Exception(orig))
case _ => ???
}
}
<console>:18: error: could not find implicit value for parameter e: M[T]
implicitly[M[T]] match {
^
<console>:19: error: value exception is not a member of object scala.concurrent.Future
case _: Future[T] => Future.exception(new Exception(orig))
^
In my opinion the simplest is to rely on good old overloading: just define a different overload for each type that you want to handle.
Now of course, there is the problem of having different overloads with the same signature, and as usual in scala, you can use tricks to work around them. Here we'll add dummy implicit parameters to force each overload to have a distinct signature. Not pretty but it works and will suffice in this case.
import scala.concurrent.Future
import scala.util.{Try, Failure}
implicit class FailureStringContext (val sc : StringContext) extends AnyVal {
def fail[T](args : Any*): Future[T] = {
Future.failed[T](new Exception(sc.s (args : _*)))
}
def fail[T](args : Any*)(implicit dummy: DummyImplicit): Option[T] = {
Option.empty[T]
}
def fail[T](args : Any*)(implicit dummy: DummyImplicit, dummy2: DummyImplicit): Try[T] = {
Failure[T](new Exception(sc.s (args : _*)))
}
}
And tada:
scala> fail"oops": Option[String]
res6: Option[String] = None
scala> fail"oops": Future[String]
res7: scala.concurrent.Future[String] = scala.concurrent.impl.Promise$KeptPromise#6fc1a8f6
scala> fail"oops": Try[String]
res8: scala.util.Try[String] = Failure(java.lang.Exception: oops)

Using Macro to Make Case Class

Given the following macro (thanks #TravisBrown for this help ):
JetDim.scala
case class JetDim(dimension: Int) {
require(dimension > 0)
}
object JetDim {
def validate(dimension: Int): Int = macro JetDimMacro.apply
def build(dimension: Int): JetDim = JetDim(validate(dimension))
}
JetDimMacro.scala
import reflect.macros.Context
object JetDimMacro {
sealed trait PosIntCheckResult
case class LteqZero(x: Int) extends PosIntCheckResult
case object NotConstant extends PosIntCheckResult
def apply(c: Context)(dimension: c.Expr[Int]): c.Expr[Int] = {
import c.universe._
getInt(c)(dimension) match {
case Right(_) => reify { dimension.splice }
case Left(LteqZero(x)) => c.abort(c.enclosingPosition, s"$x must be > 0.")
case Left(NotConstant) => reify { dimension.splice }
}
}
def getInt(c: Context)(dimension: c.Expr[Int]): Either[PosIntCheckResult, Int] = {
import c.universe._
dimension.tree match {
case Literal(Constant(x: Int)) => if (x > 0) Right(x) else Left(LteqZero(x))
case _ => Left(NotConstant)
}
}
}
It works from the REPL:
scala> import spire.math.JetDim
import spire.math.JetDim
scala> JetDim.validate(-55)
<console>:9: error: -55 must be > 0.
JetDim.validate(-55)
^
scala> JetDim.validate(100)
res1: Int = 100
But, I'd like to build this compile-time check (via the JetDimMacro) into the case class's apply method.
Attempt 1
case class JetDim(dimension: Int) {
require(dimension > 0)
}
object JetDim {
private def validate(dimension: Int): Int = macro JetDimMacro.apply
def build(dimension: Int): JetDim = JetDim(validate(dimension))
}
But that failed:
scala> import spire.math.JetDim
import spire.math.JetDim
scala> JetDim.build(-55)
java.lang.IllegalArgumentException: requirement failed
at scala.Predef$.require(Predef.scala:207)
at spire.math.JetDim.<init>(Jet.scala:21)
at spire.math.JetDim$.build(Jet.scala:26)
... 43 elided
Attempt 2
class JetDim(dim: Int) {
require(dim > 0)
def dimension: Int = dim
}
object JetDim {
private def validate(dimension: Int): Int = macro JetDimMacro.apply
def apply(dimension: Int): JetDim = {
validate(dimension)
new JetDim(dimension)
}
}
Yet that failed too:
scala> import spire.math.JetDim
import spire.math.JetDim
scala> JetDim(555)
res0: spire.math.JetDim = spire.math.JetDim#4b56f205
scala> JetDim(-555)
java.lang.IllegalArgumentException: requirement failed
at scala.Predef$.require(Predef.scala:207)
at spire.math.JetDim.<init>(Jet.scala:21)
at spire.math.JetDim$.apply(Jet.scala:30)
... 43 elided
I thought to modify JetDimMacro#apply to return a JetDim rather than an Int. However, JetDim lives in the core project, which, from what I see, depends on the macros project (where JetDimMacro lives).
How can I use this validate method from JetDim's companion object to check for positive int's at compile-time?
The problem is that by the time we call validate in apply we are no longer dealing with a constant (singleton type). So, validate gets a non-constant Int.
As an alternative, you could try using an implicit witness for positive ints, which JetDim then takes as a constructor. For instance, something like:
package com.example
case class JetDim(n: PositiveInt)
case class PositiveInt(value: Int) {
require(value > 0)
}
Then, we add an implicit (macro) conversion from Int => PositiveInt that does your check.
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
object PositiveInt {
implicit def wrapConstantInt(n: Int): PositiveInt = macro verifyPositiveInt
def verifyPositiveInt(c: Context)(n: c.Expr[Int]): c.Expr[PositiveInt] = {
import c.universe._
val tree = n.tree match {
case Literal(Constant(x: Int)) if x > 0 =>
q"_root_.com.example.PositiveInt($n)"
case Literal(Constant(x: Int)) =>
c.abort(c.enclosingPosition, s"$x <= 0")
case x =>
c.abort(c.enclosingPosition, s"cannot verify $x > 0")
}
c.Expr(tree)
}
}
You can then use JetDim(12), which will pass, or JetDim(-12), which will fail (the macro expands the Int to a PositiveInt).

Scala: Error handling and exception matching

Given the following custom Exception ...
trait ServiceException extends RuntimeException {
val errorCode: Int
}
object ServiceException {
def apply(
message: String, _errorCode: Int
): ServiceException = new RuntimeException(message) with ServiceException {
val errorCode: Int = _errorCode
}
def apply(
message: String, cause: Throwable, _errorCode: Int
): ServiceException = new RuntimeException(message, cause) with ServiceException {
val errorCode: Int = _errorCode
}
}
... and the following method returning a Future ...
myService.doSomethingAndReturnFuture.map {
...
}.recover {
case ServiceException(5) =>
Logger.debug("Error 5")
// this does not work
// case e: ServiceException(5) =>
// Logger.debug(s"Error 5: ${e.getMessage}")
case NonFatal(e) =>
Logger.error("error doing something", e)
}
... how do I get the error message from ServiceException?
You will need an unapply for your described match to work, which should be defined in the companion object.
object ServiceException {
//... apply methods
def unapply(ex: ServiceException) = Some(ex.errorCode)
}
And then you can match.
recover {
case se#ServiceException(5) => println(s"Error 5: ${se.getMessage}")
case _ => println("Some other error")
}
You could also include the message in the unapply.
def unapply(ex: ServiceException) = Some((ex.errorCode, ex.getMessage))
and then match like this:
recover {
case ServiceException(5, msg) => println(s"Error 5: $msg")
case _ => println("Some other error")
}
As an alternative you can also do it without the unapply. Then it could look like:
recover {
case se: ServiceException if se.errorCode == 5 => println(s"Error 5: ${se.getMessage}")
case _ => println("Some other error")
}
People like case classes.
This does not exactly align with your givens, but for example:
scala> trait ServiceException { _: RuntimeException => def errorCode: Int }
defined trait ServiceException
scala> case class MyX(errorCode: Int, msg: String, cause: Exception = null) extends RuntimeException(msg, cause) with ServiceException
defined class MyX
scala> def i: Int = throw MyX(42, "Help!")
i: Int
scala> import concurrent._ ; import ExecutionContext.Implicits._
import concurrent._
import ExecutionContext.Implicits._
scala> Future(i) recover { case MyX(code, m, err) => println(m) ; -1 }
res11: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise#7d17ee50
scala> Help!
scala> .value
res12: Option[scala.util.Try[Int]] = Some(Success(-1))

How to create a method which invokes another service and return a Future?

I want to define a method, which will return a Future. And in this method, it will call another service which returns also a Future.
We have defined a BusinessResult to represent Success and Fail:
object validation {
trait BusinessResult[+V] {
def flatMap[T](f: V => BusinessResult[T]):BusinessResult[T]
def map[T](f: V => T): BusinessResult[T]
}
sealed case class Success[V](t:V) extends BusinessResult[V] {
def flatMap[T](f: V => BusinessResult[T]):BusinessResult[T] = {
f(t)
}
def map[T](f: V => T): BusinessResult[T] = {
Success(f(t))
}
}
sealed case class Fail(e:String) extends BusinessResult[Nothing] {
def flatMap[T](f: Nothing => BusinessResult[T]):BusinessResult[T] = this
def map[T](f: Nothing => T): BusinessResult[T] = this
}
}
And define the method:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import validation._
def name: BusinessResult[String] = Success("my name")
def externalService(name:String):Future[String] = future(name)
def myservice:Future[Int] = {
for {
n <- name
res <- externalService(n)
} yield res match {
case "ok" => 1
case _ => 0
}
}
But which is not compilable. The code in myservice can't return a Future[Int] type.
I also tried to wrap the name with Future:
def myservice:Future[Int] = {
for {
nn <- Future.successful(name)
n <- nn
res <- externalService(n)
} yield res match {
case "ok" => 1
case _ => 0
}
}
Which is also not compilable.
I know there must be a lot of issues in this code. How can I adjust them to make it compilable?
If you change the n with some hardcoded string it works, the problem is that in the for comprehension the variable n has type BusinessResult[String], as you probably already know for comprehension desugarize to map, flatMap and filter so the first part n <- name desugarize to a map on name:
val test: BusinessResult[String] = name.map(x => x)
Intellij thinks n is a String but the scala compiler disagree:
type mismatch;
[error] found : validation.BusinessResult[Nothing]
[error] required: scala.concurrent.Future[Int]
[error] n <- name
[error] ^
Easy solution could be to add a getter method to get back the string and do something like Option does:
object validation {
trait BusinessResult[+V] {
def flatMap[T](f: V => BusinessResult[T]):BusinessResult[T]
def map[T](f: V => T): BusinessResult[T]
def getVal: V
}
sealed case class Success[V](t:V) extends BusinessResult[V] {
def flatMap[T](f: V => BusinessResult[T]):BusinessResult[T] = {
f(t)
}
def map[T](f: V => T): BusinessResult[T] = {
Success(f(t))
}
def getVal: V = t
}
sealed case class Fail(e:String) extends BusinessResult[Nothing] {
def flatMap[T](f: Nothing => BusinessResult[T]):BusinessResult[T] = this
def map[T](f: Nothing => T): BusinessResult[T] = this
def getVal = throw new Exception("some message")
}
}
def myservice: Future[Int] = {
val value = name.getVal
for {
res <- externalService(value)
} yield res match {
case "ok" => 1
case _ => 0
}
}
Note that you can't extract the name in the for comprehension since map on String return Chars