Skip to content

Instantly share code, notes, and snippets.

@bmc
Created April 6, 2013 16:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bmc/5326616 to your computer and use it in GitHub Desktop.
Save bmc/5326616 to your computer and use it in GitHub Desktop.
Example comparison of Future functions and async library
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scalaz._
import Scalaz._
import scala.async.Async.{async, await}
import lib.ScalazUtil
// Stubs, to get this to compile. Fill in with real stuff later.
case class User(username: String, password: String)
case class GitHubData(user: User)
case class Link(user: User)
case class Blog(user: User)
case class Recommendation(user: User)
sealed case class CollectedUserData(
gitHubData: Option[GitHubData],
links: Option[Seq[Link]],
blogs: Option[Seq[Blog]],
recommendations: Option[Seq[Recommendation]]
)
class UserDataLoader {
/** Version that uses regular Future combinators.
*/
def getUserData1(user: User): Future[Validation[String, CollectedUserData]] = {
// Types shown, for clarity.
val fGH: Future[Validation[String, Option[GitHubData]]] = Future {
loadGitHubData(user)
}
val fLinks: Future[Validation[String, Option[Seq[Link]]]] = Future {
loadWebSites(user)
}
val fBlogs: Future[Validation[String, Option[Seq[Blog]]]] = Future {
loadBlogs(user)
}
val fRec: Future[Validation[String, Option[Seq[Recommendation]]]] = Future {
loadRecommendations(user)
}
for {vGH <- fGH
vLinks <- fLinks
vBlogs <- fBlogs
vRec <- fRec}
yield {
// These are all validations. Convert them.
val combinedNEL = (vGH.liftFailNel |@|
vLinks.liftFailNel |@|
vBlogs.liftFailNel |@|
vRec.liftFailNel)
// Combined is an applicative functor. Call it and map the result.
val resNEL = combinedNEL {
case (gh, links, blogs, rec) =>
CollectedUserData(gh, links, blogs, rec)
}
// Convert the resulting ValidationNEL into a Validation, with the
// failure strings (if any) combined via a delimiter.
ScalazUtil.failNelToFailure(resNEL)
}
}
/** Version that uses async library. This is cleaner (arguably), shorter, and
* likely to be more efficient.
*/
def getUserData2(user: User): Future[Validation[String, CollectedUserData]] = {
// Types shown, for clarity.
val fGH: Future[Validation[String, Option[GitHubData]]] = Future {
loadGitHubData(user)
}
val fLinks: Future[Validation[String, Option[Seq[Link]]]] = Future {
loadWebSites(user)
}
val fBlogs: Future[Validation[String, Option[Seq[Blog]]]] = Future {
loadBlogs(user)
}
val fRec: Future[Validation[String, Option[Seq[Recommendation]]]] = Future {
loadRecommendations(user)
}
// Map the individual futures into a combined future of CollectedUserData.
async {
// The futures all return Validation[String, _]. Convert them into
// ValidationNEL objects.
val combinedNEL = (await(fGH).liftFailNel |@|
await(fLinks).liftFailNel |@|
await(fBlogs).liftFailNel |@|
await(fRec).liftFailNel)
// combinedNEL is an applicative functor. Call it and map the result
// to a single ValidationNEL[String, CollectedUserData]. Then, map the
// result to a Validation[String, CollectedUserData]
val resNEL = combinedNEL {
case (gh, links, blogs, rec) =>
CollectedUserData(gh, links, blogs, rec)
}
// This is a utility method that maps a ValidationNEL[String, T] to
// a Validation[String, T], combining the failure strings (if any)
// with a delimiter. The delimiter defaults to "; ".
ScalazUtil.failNelToFailure(resNEL)
}
}
// More stubs.
private def loadGitHubData(user: User): Validation[String, Option[GitHubData]] = {
Some(GitHubData(user)).success
}
private def loadWebSites(user: User): Validation[String, Option[Seq[Link]]] = {
Some(Seq(Link(user))).success
}
private def loadBlogs(user: User): Validation[String, Option[Seq[Blog]]] = {
Some(Seq(Blog(user))).success
}
private def loadRecommendations(user: User): Validation[String, Option[Seq[Recommendation]]] = {
Some(Seq(Recommendation(user))).success
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment