by Ted Naleid & Joe Muraski
getUser: User
getUsers: List[User]
(as documented by the Gang of Four)
val adults = users.filter(_.age > 17).sortBy(p => (p.lName, p.fName)).take(10)
CPS - Continuation Passing Style
Call Back Hell
show easy then painful examples
(for single values)
getWidget: Future[Widget]
One way is to request the full list in an asynchronous way:
getWidgets: Future[Widget]
Server calculates list asynchronously and does a callback when it has the full list
Problems: - need to wait for full list to come back (slow user experience) - what if it's infinite (need to paginate, etc) - what if it's a stream that updates? we need to poll for updates
lets you register a callback
but then it is up to you to aggregate those into mutable lists and let consumers know that the list has been updated
You got your Iterator in my Observable! You got your Observable in my Iterator!
Photoshopped Reeses Peanut Butter Cups image
getWidgets: Observable[Widget]
Allows you to asynchronously get
They are also composable, as we will see
netflix does this with their video API:
def getVideos(userId: Long): Observable[Map[String, Any]] = videoService.getVideos(userId) .take(10) // take the first 10, then auto-unsubscribe .flatMap(video => { val metadata = video.getMetaData(video) // async Map val bookmark = videoService.getBookmark(video, userId) // async Map val rating = videoService.getRating(video, userId) // async Map Observable.zip(Observable(List(metadata, bookmark, rating): _*)).map { case m :: b :: r :: Nil => Map("id" -> video.id) ++ m ++ b ++ r } }) //=> Map(id -> 1, rating -> *****, pos -> 1:33, length -> 2h, title -> Gravity)
That method composes 4 separate asynch calls into a List of 10 Maps
None of them are in Java, reasoning about asynchronous code is easier in more expressive languages