Implementing null safe logic in Scala Futures map and flatmap - scala

My code consists of a number of scala.concurrent.Futures returned from invoking Akka actors
So sample code in my actor would be something like the following:
val ivResult: Future[Any] = ask(ivActor, ivId)
// perform mapping is a function of type (Any) => Unit
val ivMapping: Future[Unit] = ivResult.map(performingMapping)
// erLookup is a function of type (Any) => Future[Any]
val erResult: Future[Any] = ivResult.flatMap(erLookup)
And so on. Code basically consists of future.flatmap().map() to perform aggregation logic
My problem is that I want to implement null-safe logic such that if the result of a future is null then we don't throw NullPointerExceptions
Obviously, I can embed null-safe checks in each of my functions, but these seems a little verbose considering Scala's powerful capabilities.
Therefore, I'm looking to find out if there is a more elegant way to do this, perhaps using implicits etc.

The result of a Future already indicates whether it completed successfully.
Normally, on NPE your code would blow up and the future is failed.
You're saying, Please don't let my code blow up, with possibly deleterious side effects.
So you want a guard with a special failure state.
Something like:
scala> object DeadFuture extends Exception with NoStackTrace
defined object DeadFuture
scala> implicit class SafeFuture[A](val f: Future[A]) {
| def safeMap[B](m: A => B)(implicit x: ExecutionContext) =
| f.map { a: A => if (a == null) throw DeadFuture else m(a) }(x)
| def safeFlatMap[B](m: A => Future[B])(implicit x: ExecutionContext) =
| f.flatMap { a: A => if (a == null) (Future failed DeadFuture) else m(a) }(x)
| }
then
scala> case class Datum(i: Int)
defined class Datum
scala> def f(d: Datum): Int = 2 * d.i
f: (d: Datum)Int
scala> def g(d: Datum): Future[Int] = Future(2 * d.i)
g: (d: Datum)scala.concurrent.Future[Int]
scala> Future[Datum](null) safeMap f
res1: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise#5fa5debb
scala> .value
res3: Option[scala.util.Try[Int]] = Some(Failure(DeadFuture$))
scala> def g(d: Datum): Future[Int] = Future(2 * d.i)
g: (d: Datum)scala.concurrent.Future[Int]
scala> Future[Datum](null) safeFlatMap g
res4: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise#7f188fd
scala> .value
res5: Option[scala.util.Try[Int]] = Some(Failure(DeadFuture$))
There might be a better way to induce the conversion, so you keep for-comprehensions.
for (i <- safely(futureInt)) f(i)

Related

How to reduce Seq of functions that return Either with short circuit behavior?

Take the following example (adapted from the cats Either documentation).
Three validation functions are being applied in sequence each returning an Either. If the application of any of the functions fails a Left value is returned.
object Validators {
def isBiggerThan5(i: Int): Either[Exception, Int] =
if (i > 5) Either.right(i)
else Either.left(new NumberFormatException(s"${i} is smaller than 5."))
def isSmallerThan20(i: Int): Either[Exception, Int] =
if (i < 20) Either.right(i)
else Either.left(new NumberFormatException(s"${i} is bigger than 20."))
def isEven(i: Int): Either[Exception, Int] =
if (i % 2 == 0) Either.right(i)
else Either.left(new NumberFormatException(s"${i} is not an even number."))
}
import Validators._
def magic(i: Int): Either[Exception, Int] =
isBiggerThan5(i).flatMap(isSmallerThan20).flatMap(isEven)
Now imagine the three validation functions are passed as arguments:
type Ops = Int => Either[Exception, Int]
def magic(ops: Seq[Ops])(s: String): Either[Exception, String] =
??? // How to apply ops in sequence with short circuit behavior?
println(magic(Seq(isBiggerThan5, isSmallerThan20, isEven)))
How can we evaluate the Seq[Ops] one after another with short circuit behavior? I have played around with Seq.foldLeft or Seq.reduce but could not quite figure it out.
I am not interested in error accumulation. It should simply fail on the first validator that returns a Left.
foldLeftM should work.
import cats.syntax.all._
def verify(i: Int, ops: Vector[Ops]): Either[Exception, Int] =
ops.foldLeftM(i)((i, o) => o(i))
I agree the best solution is to use foldLeftM
However, just for sake of completeness if you want a more vanilla solution, this is a perfect use case for List and tail-recursion.
type Ops[A] = A => Either[Exception, A]
def magic[A](initial: A)(ops: List[Ops[A]): Either[Exception, A] = {
#annotation.tailrec
def loop(remaining: List[Ops[A]], current: A): Either[Exception, A] =
remaining match {
case step :: tail =>
step(current) match {
case Right(next) =>
loop(remaining = tail, current = next)
case left # Left(_) =>
left
}
case Nil =>
Right(current)
}
loop(remaining = ops, current = initial)
}
(after looking at all this boilerplate is when you start to appreciate cats)

Stacking monads Writer and OptionT

I have the following code:
override def getStandsByUser(email: String): Try[Seq[Stand]] =
(for {
user <- OptionT(userService.findOneByEmail(email)): Try[Option[User]]
stands <- OptionT.liftF(standService.list()):[Try[List[Stand]]]
filtered = stands.filter(stand => user.stands.contains(stand.id))
} yield filtered).getOrElse(Seq())
}
I want to add logging on each stage of the processing - so I need to introduce writer monad and stack it with monad transformer OptionT. Could you please suggest how to do that?
The best way to do this is to convert your service calls into using cats-mtl.
For representing Try or Option you can use MonadError and for logging you can use FunctorTell. Now I don't know what exactly you're doing inside your userService or standService, but I wrote some code to demonstrate what the result might look like:
type Log = List[String]
//inside UserService
def findOneByEmail[F[_]](email: String)
(implicit F: MonadError[F, Error], W: FunctorTell[F, Log]): F[User] = ???
//inside StandService
def list[F[_]]()
(implicit F: MonadError[F, Error], W: FunctorTell[F, Log]): F[List[Stand]] = ???
def getStandsByUser[F[_]](email: String)
(implicit F: MonadError[F, Error], W: FunctorTell[F, Log]): F[List[Stand]] =
for {
user <- userService.findOneByEmail(email)
stands <- standService.list()
} yield stands.filter(stand => user.stands.contains(stand.id))
//here we actually run the function
val result =
getStandsByUser[WriterT[OptionT[Try, ?], Log, ?] // yields WriterT[OptionT[Try, ?], Log, List[Stand]]
.run // yields OptionT[Try, (Log, List[Stand])]
.value // yields Try[Option[(Log, List[Stand])]]
This way we can avoid all of the calls to liftF and easily compose our different services even if they will use different monad transformers at runtime.
If you take a look at the definition of cats.data.Writer you will see that it is an alias to cats.data.WriterT with the effect fixed to Id.
What you want to do is use WriterT directly and instead of Id use OptionT[Try, YourType].
Here is a small code example of how that can be achieved:
object Example {
import cats.data._
import cats.implicits._
type MyType[A] = OptionT[Try, A]
def myFunction: MyType[Int] = OptionT(Try(Option(1)))
def main(args: Array[String]): Unit = {
val tmp: WriterT[MyType, List[String], Int] = for {
_ <- WriterT.tell[MyType, List[String]](List("Before first invocation"))
i <- WriterT.liftF[MyType, List[String], Int](myFunction)
_ <- WriterT.tell[MyType, List[String]](List("After second invocation"))
j <- WriterT.liftF[MyType, List[String], Int](myFunction)
_ <- WriterT.tell[MyType, List[String]](List(s"Result is ${i + j}"))
} yield i + j
val result: Try[Option[(List[String], Int)]] = tmp.run.value
println(result)
// Success(Some((List(Before first invocation, After second invocation, Result is 2),2)))
}
}
The type annotations make this a bit ugly, but depending on your use case you might be able to get rid of them. As you can see myFunction returns a result of type OptionT[Try, Int] and WriterT.lift will push that into a writer object that also has a List[String] for your logs.

Accumulating only validation errors in Scalaz

I am a beginner in the work of functional programming and I have a sequence of ValidationNEL[A,B] and I would like to accumulate the errors into a new ValidationNEL[A,B]. This depends on the fact that B
is a mutable data structure coming from legacy code, and so it would be oververbose to hold a Seq[B].
I know from other posts that cumulating errors and success is possible through the sequence method: Processing a list of Scalaz6 Validation
From my understanding it all comes to writing a proper Applicative and maybe a proper Traverse.
trait MA[M[_], A] extends PimpedType[M[A]] with MASugar[M, A] {
def sequence[N[_], B](implicit a: A <:< N[B], t: Traverse[M], n: Applicative[N]): N[M[B]] =
traverse((z: A) => (z: N[B]))
def traverse[F[_],B](f: A => F[B])(implicit a: Applicative[F], t: Traverse[M]): F[M[B]] =
t.traverse(f, value)
}
How do I start? When I tried to look into Scalaz source code to find out how to implement my Applicative, I got extremely confused. I was not even able to find out which applicative allows accumulating both failures and success in Validation.
Late to the party, but as of Scalaz 7.0.4, we can do this:
def takeLastSuccess[A, B](seq: Seq[ValidationNel[A, B]]) = {
implicit val useLast = Semigroup.lastSemigroup[B]
seq reduceLeft (_ +++ _)
}
Now that I understand your question a little better, this is pretty straight forward:
def takeLastSuccess[A, B](seq:Seq[ValidationNEL[A, B]]) =
seq.sequence[({type l[a] = ValidationNEL[A, a]})#l, B].map(_.last)
When you sequence this Scala has some trouble with the types so you need to use a type lambda. Sequence is a nice shortcut to go from Seq[Something[X]] to Something[Seq[X]]. Finally, we just map the success and get the last B from the sequence of B's.
Going off the example from the post you cited, here's what I get from the REPL:
scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._
scala> type ExceptionsOr[A] = ValidationNEL[Exception, A]
defined type alias ExceptionsOr
scala> val successResults: Seq[ExceptionsOr[Int]] = Seq(
| "13".parseInt.liftFailNel, "42".parseInt.liftFailNel
| )
successResults: Seq[ExceptionsOr[Int]] = List(Success(13), Success(42))
scala> val failResults: Seq[ExceptionsOr[Int]] = Seq(
| "13".parseInt.liftFailNel, "a".parseInt.liftFailNel, "b".parseInt.liftFailNel
| )
failResults: Seq[ExceptionsOr[Int]] = List(Success(13), Failure(NonEmptyList(java.lang.NumberFormatException: For input string: "a")), Failure(NonEmptyList(java.lang.NumberFormatException: For input string: "b")))
scala> def takeLastSuccess[A, B](seq:Seq[ValidationNEL[A, B]]) = seq.sequence[({type l[a] = ValidationNEL[A, a]})#l, B].map(_.last)
takeLastSuccess: [A, B](seq: Seq[scalaz.Scalaz.ValidationNEL[A,B]])scalaz.Validation[scalaz.NonEmptyList[A],B]
scala> takeLastSuccess(successResults)
res0: scalaz.Validation[scalaz.NonEmptyList[Exception],Int] = Success(42)
scala> takeLastSuccess(failResults)
res1: scalaz.Validation[scalaz.NonEmptyList[Exception],Int] = Failure(NonEmptyList(java.lang.NumberFormatException: For input string: "a", java.lang.NumberFormatException: For input string: "b"))

Scala, partial functions

Is there any way to create a PartialFunction except through the case statement?
I'm curious, because I'd like to express the following (scala pseudo ahead!)...
val bi = BigInt(_)
if (bi.isValidInt) bi.intValue
... as a partial function, and doing
val toInt : PartialFunction[String, Int] = {
case s if BigInt(s).isValidInt => BigInt(s).intValue
}
seems redundant since I create a BigInt twice.
Not sure I understand the question. But here's my attempt: Why not create an extractor?
object ValidBigInt {
def unapply(s: String): Option[Int] = {
val bi = BigInt(s)
if (bi.isValidInt) Some(bi.intValue) else None
}
}
val toInt: PartialFunction[String, Int] = {
case ValidBigInt(i) => i
}
The other option is (and that may answer the question as to whether one can create PartialFunction other than with a case literal):
val toInt = new PartialFunction[String, Int] {
def isDefinedAt(s: String) = BigInt(s).isValidInt
def apply(s: String) = BigInt(s).intValue
}
However since the idea of a partial function is that it's only partially defined, in the end you will still do redundant things -- you need to create a big int to test whether it's valid, and then in the function application you create the big int again...
I saw a project at Github that tried to come around this by somewhat caching the results from isDefinedAt. If you go down to the benchmarks, you'll see that it turned out to be slower than the default Scala implementation :)
So if you want to get around the double nature of isDefinedAt versus apply, you should just go straight for a (full) function that provides an Option[Int] as result.
I think you're looking for lift/unlift. lift takes a partial function and turns it into a function that returns an Option. Unlift takes a function with one argument that returns an option, and returns a partial function.
import scala.util.control.Exception._
scala> def fn(s: String) = catching(classOf[NumberFormatException]) opt {BigInt(s)}
fn: (s: String)Option[scala.math.BigInt]
scala> val fnPf = Function.unlift(fn)
fnPf: PartialFunction[String,scala.math.BigInt] = <function1>
scala> val fn = fnPf.lift
fn: String => Option[scala.math.BigInt] = <function1>
Closely related, you also want to look at this answer for information about cond and condOpt:
scala> import PartialFunction._
import PartialFunction._
scala> cond("abc") { case "def" => true }
res0: Boolean = false
scala> condOpt("abc") { case x if x.length == 3 => x + x }
res1: Option[java.lang.String] = Some(abcabc)
You can write out a PartialFunction "longhand" if you'd like:
object pf extends PartialFunction[Int,String] {
def isDefinedAt(in: Int) = in % 2 == 0
def apply(in: Int) = {
if (in % 2 == 0)
"even"
else
throw new MatchError(in + " is odd")
}
Okay, I got this
import java.lang.NumberFormatException
import scala.util.control.Exception._
val toInt: PartialFunction[String, Int] = {
catching(classOf[NumberFormatException]) opt BigInt(_) match {
case Some(bi) if bi.isValidInt => bi.intValue
}
}
How about this?
val toInt: PartialFunction[String, Int] = (s: String) => BigInt(s) match {
case bi if bi.isValidInt => bi.intValue
}

Cost of using repeated parameters

I consider refactoring few method signatures that currently take parameter of type List or Set of concrete classes --List[Foo]-- to use repeated parameters instead: Foo*.
Update: Following reasoning is flawed, move along...
This would allow me to use the same method name and overload it based on the parameter type. This was not possible using List or Set, because List[Foo] and List[Bar] have same type after erasure: List[Object].
In my case the refactored methods work fine with scala.Seq[Foo] that results from the repeated parameter. I would have to change all the invocations and add a sequence argument type annotation to all collection parameters: baz.doStuffWith(foos:_*).
Given that switching from collection parameter to repeated parameter is semantically equivalent, does this change have some performance impact that I should be aware of?
Is the answer same for scala 2.7._ and 2.8?
When Scala is calling a Scala varargs method, the method will receive an object that extends Seq. When the call is made with : _*, the object will be passed as is*, without copying. Here are examples of this:
scala> object T {
| class X(val self: List[Int]) extends SeqProxy[Int] {
| private val serial = X.newSerial
| override def toString = serial.toString+":"+super.toString
| }
| object X {
| def apply(l: List[Int]) = new X(l)
| private var serial = 0
| def newSerial = {
| serial += 1
| serial
| }
| }
| }
defined module T
scala> new T.X(List(1,2,3))
res0: T.X = 1:List(1, 2, 3)
scala> new T.X(List(1,2,3))
res1: T.X = 2:List(1, 2, 3)
scala> def f(xs: Int*) = xs.toString
f: (Int*)String
scala> f(res0: _*)
res3: String = 1:List(1, 2, 3)
scala> f(res1: _*)
res4: String = 2:List(1, 2, 3)
scala> def f(xs: Int*): Seq[Int] = xs
f: (Int*)Seq[Int]
scala> def f(xs: Int*) = xs match {
| case ys: List[_] => println("List")
| case _ => println("Something else")
| }
f: (Int*)Unit
scala> f(List(1,2,3): _*)
List
scala> f(res0: _*)
Something else
scala> import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.ArrayBuffer
scala> def f(xs: Int*) = xs match {
| case ys: List[_] => println("List")
| case zs: ArrayBuffer[_] => zs.asInstanceOf[ArrayBuffer[Int]] += 4; println("Array Buffer")
| case _ => println("Something else")
| }
f: (Int*)Unit
scala> val ab = new ArrayBuffer[Int]()
ab: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
scala> ab + 1
res11: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1)
scala> ab + 2
res12: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2)
scala> ab + 3
res13: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3)
scala> f(ab: _*)
Array Buffer
scala> ab
res15: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4)
Note
An Array is passed as a WrappedArray. There's no copying of elements involved, however, and changes to the WrappedArray will be reflected in the Array.
Your reason for replacing List[T] with T* is flawed: Scala will not allow overloading like
class Foo
{
def t1(x : Int*) = println("Ints")
def t1(x : Strings*) = println("Strings")
}
This will result in the same compiler error as using List[Int]/List[String] here.
Although a bit clumsy you could use
class Foo
{
def t1(x0 : Int,x : Int*) = println("Ints")
def t1(x0 : String,x : Strings*) = println("Strings")
}
but that requires special treatment of the first parameter versus the rest.
Gr. Silvio
In the simplest terms, all the arguments that correspond to a repeated formal parameters, regardless of their origin, must be copied to a sequential collection of some sort for presentation to the method. The details of exactly what kind of sequence is used vary with Scala version and possibly with the source of the arguments. But regardless of those details, it is an O(n) operation, though the cost per item is pretty low. There will be at least one and sometimes more instance allocations for the sequence itself.
Randall Schulz