Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>(Edited to give a correct answer!)</p> <p>The key here is that <code>Future</code> and <code>Option</code> <em>don't compose inside <code>for</code></em> because there aren't the correct <code>flatMap</code> signatures. As a reminder, for desugars like so:</p> <pre><code>for ( x0 &lt;- c0; w1 = d1; x1 &lt;- c1 if p1; ... ; xN &lt;- cN) yield f c0.flatMap{ x0 =&gt; val w1 = d1 c1.filter(x1 =&gt; p1).flatMap{ x1 =&gt; ... cN.map(xN =&gt; f) ... } } </code></pre> <p>(where any <code>if</code> statement throws a <code>filter</code> into the chain--I've given just one example--and the equals statements just set variables before the next part of the chain). Since you can only <code>flatMap</code> other <code>Future</code>s, every statement <code>c0</code>, <code>c1</code>, ... except the last had better produce a <code>Future</code>.</p> <p>Now, <code>getUserDetails</code> and <code>getSchool</code> both produce <code>Futures</code>, but <code>sid</code> is an <code>Option</code>, so we can't put it on the right-hand side of a <code>&lt;-</code>. Unfortunately, there's no clean out-of-the-box way to do this. If <code>o</code> is an option, we can</p> <pre><code>o.map(Future.successful).getOrElse(Future.failed(new Exception)) </code></pre> <p>to turn an <code>Option</code> into an already-completed <code>Future</code>. So</p> <pre><code>for { ud &lt;- userStore.getUserDetails(user.userId) // RHS is a Future[Either[...]] sid = ud.right.toOption.flatMap(_.schoolId) // RHS is an Option[Int] fid &lt;- sid.map(Future.successful).getOrElse(Future.failed(new Exception)) // RHS is Future[Int] s &lt;- schoolStore.getSchool(fid) } yield s </code></pre> <p>will do the trick. Is that better than what you've got? Doubtful. But if you</p> <pre><code>implicit class OptionIsFuture[A](val option: Option[A]) extends AnyVal { def future = option.map(Future.successful).getOrElse(Future.failed(new Exception)) } </code></pre> <p>then suddenly the for-comprehension looks reasonable again:</p> <pre><code>for { ud &lt;- userStore.getUserDetails(user.userId) sid &lt;- ud.right.toOption.flatMap(_.schoolId).future s &lt;- schoolStore.getSchool(sid) } yield s </code></pre> <p>Is this the best way to write this code? Probably not; it relies upon converting a <code>None</code> into an exception simply because you don't know what else to do at that point. This is hard to work around because of the design decisions of <code>Future</code>; I'd suggest that your original code (which invokes a filter) is at least as good of a way to do it.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload