I find that I am running into the below pattern allot and I can't get it to work or look nice style wise.
I have a for comprehension that is return Futures, and then I build my model to display in a view. But before I return the Result in my Action, I sometimes have to branch using an if clause and potentially load more data.
The below code doesn't compile currently, what do you suggest I do to make the below code follow correct style with this type of pattern?
It doesn't compile because the inner for compr is return a Future[Option[Something]] but I have defined c as Option[Something]
for {
a <- fooService.getA()
b <- fooService.getB()
} yield {
var c: Option[Something] = None
if(a.size > 0) {
c = for {
c <- fooService.getC()
} yield {
Some(c)
}
}
}
val model = FooModel(a, b, c)
Ok(views.html.foo.show(model))
My view model is defined as:
FooModel(a: A, b: B, c: Option[Something])
This seems reasonably clear:
for {
a <- fooService.getA()
b <- fooService.getB()
c <- if (a.nonEmpty) fooService.getC() else Future.successful(None)
} yield {
val model = FooModel(a, b, c)
Ok(views.html.foo.show(model))
}
Extract the if (a.nonEmpty) fooService.getC() else Future.successful(None)
to another method or service if you want.
Now it compiles, but have you noticed, that your program runs sequentially?
object fooService{
def getA() = {
Future{
println("I'm getA")
for(i <- 1 to 10){
println(".")
Thread.sleep(200)
}
"A"
}
}
def getB() = {
Future{
println("I'm getB")
for(i <- 1 to 10){
println(".")
Thread.sleep(200)
}
"B"
}
}
}
object Main {
def main(args: Array[String]) ={
for {
a <- fooService.getA()
b <- fooService.getB()
} println(a + b)
Thread.sleep(4000)
}
}
This is the output:
I'm getA
.
.
.
.
.
.
.
.
.
.
I'm getB
.
.
.
.
.
.
.
.
.
.
AB
And with a little change:
object fooService{
def getA() = {
Future{
println("I'm getA")
for(i <- 1 to 10){
println(".")
Thread.sleep(200)
}
"A"
}
}
def getB() = {
Future{
println("I'm getB")
for(i <- 1 to 10){
println(".")
Thread.sleep(200)
}
"B"
}
}
}
object Main {
def main(args: Array[String]) ={
val f1 = fooService.getA()
val f2 = fooService.getB()
for {
a <- f1
b <- f2
} println(a + b)
Thread.sleep(4000)
}
}
Output:
I'm getA
I'm getB
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
AB