0

What is the difference in how you handle a Future[User] versus a Future[Option[User]]?

I am also confused as I kind of thought a flatMap removes Options, but is that restricted to them being in a collection?

cool breeze
  • 4,461
  • 5
  • 38
  • 67

2 Answers2

1

No, flatMap does not remove Option. This is a mistaken but common belief brought upon by the fact that there is an implicit conversion from Option to Traversable that allows you do to things like List(Option(1)).flatMap(x => x) (essentially .flatten.)

Instead, think of flatMap the same way you would do with something more akin to a Monad. Given some type M[_] and a function of type A => M[B] produce a M[B]. So, for flatMap to work for you in this case, you'd have to have a function of type Option[User] => Future[B] for some type B.

def doSomething(ouser: Option[User]): Future[Output] = { ...

val res: Future[Output] = futOptUser.flatMap(doSomething)
wheaties
  • 35,646
  • 15
  • 94
  • 131
  • I want Option[User] as my final result. – cool breeze Dec 07 '15 at 19:35
  • I'm not so sure that "think of flatMap the same way you would do with something more akin to a Monad" is the right answer to a person that thought of `flatMap` as something that "removes" `Option`. – ziggystar Dec 07 '15 at 19:42
  • 1
    @ziggystar How would you say it? The biggest issue is that stupid implicit conversion. It really does confuse the issue on many fronts. – wheaties Dec 07 '15 at 20:08
  • 1
    @coolbreeze the only way to get out of a `Future` is using `Await`. A `Future` isn't a collection. It's something that represents a value that will exist at some point in the future. – wheaties Dec 07 '15 at 20:09
  • In a play app, would you pass a future down to the view page? I mean you have to block at some point right? – cool breeze Dec 07 '15 at 20:39
1

I suggest you to read and understand docs.

In brief, without blocking you can:

  • transform result of the future (using map)
  • combine results of several futures (using flatMap)
  • add completion callback (using onComplete)

You can synchronously wait for future termination using Await to get unwrapped value, but this usually doesn't make much sense (as you are blocking your current thread).

Better add onComplete or onSuccess callback to your future (which will receive unwrapped future's result as parameter):

 val userFuture: Future[Option[User]] = Future { getUserOption() }
 userFuture.onSuccess {
    case userOpt:Option[User] => userOpt.foreach {  user =>
       println(user)  // watch out for thread-safety here!
    }    
 }
Aivean
  • 10,692
  • 25
  • 39
  • What do you mean watch out for thread safety here? In a Play application how could this be a problem? – cool breeze Dec 08 '15 at 15:30
  • @coolbreeze Just keep in mind that Future's body and callback may be executed in different threads. Unfortunately I'm not familiar with play and hence can't tell which parts of it are potentially thread-unsafe. – Aivean Dec 08 '15 at 18:51