Created
April 6, 2013 16:09
-
-
Save bmc/5326616 to your computer and use it in GitHub Desktop.
Example comparison of Future functions and async library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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