How do you manage nesting from callbacks and matches and such? Inlining short functions like _ + _ is fine, but how do you organize more advanced operations?
(I'm just constantly looking for ways to make my scala code more accessible.)
I am indeed referring to for-comprehensions. Any time you have nested flatMap/maps you can replace it with a for, since that's all a for-comprehension really is...
Or, since I'm using the async Postgres module which returns Futures, to make them run in parallel you need to create the futures beforehand. I often have something like this...
val fProject = Project.findById(projectId)
val fTask = Task.findById(taskId)
for {
projectOption <- fProject
taskOption <- fTask
students <- projectOption match {
case Some(project) => Student.findByProject(projectId)
case None => Future.successful(IndexedSeq[Student]())
}
result <- (projectOption, taskOption) match {
case (Some(project), Some(task)) => {
/* do something with project, task and students */
}
case (None, _) => Future.successful(NotFound(s"Project $projectId not found"))
case (_, None) => Future.successful(NotFound(s"Task $taskId not found"))
}
}
yield result
By creating the futures first, they both run in parallel and their results are 'collected' by the for comprehension. In the first example, the computations necessarily run in sequence.
I'm using Play framework, for me, these for comprehensions are usually found in my controllers and the final result is an HTTP result.
Passing along failure can still be tricky but I find this much more organized than nesting callbacks.
(I'm just constantly looking for ways to make my scala code more accessible.)