Blog

Abstraction over future information

Often, you can extend the utility of futures with simple abstraction. In this example we’ll leverage a web service to write an internal API that will tell us the temperature in a US city.

Palling around with Weather Underground 

In one method we’ll contain the construction of the request. In this case it’s an endpoint with all of the parameters in path elements.

import dispatch._, Defaults._case class Location(city: String, state: String)def weatherSvc(loc: Location) = {  host("api.wunderground.com") / "api" / "5a7c66db0ba0323a" /     "conditions" / "q" / loc.state / (loc.city + ".xml")}

Note: Yes, that’s an API key. Use it sparingly to learn Dispatch in the Scala console, but get your own key if you are building some kind of actual weather application. We may reset this key at any time.

With this method we can bind to a handler that prints out the response in the usual way:

val nyc = Location("New York", "NY")for (str <- Http(weatherSvc(nyc) OK as.String))  println(str)

If you’re pasting along in the Scala console, you’ll see a bunch of raw XML.

Parsing XML 

Luckily, dispatch has another built-in handler for services that respond in this format.

def weatherXml(loc: Location) =  Http(weatherSvc(loc) OK as.xml.Elem)

This method returns a future scala.xml.Elem. Note that Dispatch handlers, like as.String and as.xml.Elem, mimic the name of the type they produce. They’re all under the package dispatch.as where you can access them without additional imports.

Traversing XML 

At this stage we’re working with a higher abstraction. The Http instance used to perform the request has become an implementation detail that weatherXml callers need not concern themselves with. We can use our new method to print a nicely formatted response.

def printer = new scala.xml.PrettyPrinter(90, 2)for (xml <- weatherXml(nyc))  println(printer.format(xml))

Looking at the structure of the document, we can extract the temperature of the location in degrees Celsius by searching for the element “temp_c” using the \\ method of xml.Elem.

def extractTemp(xml: scala.xml.Elem) = {  val seq = for {    elem <- xml \\ "temp_c"  } yield elem.text.toFloat  seq.head}

Temperature of the future 

With this we can create another high-level access method:

def temperature(loc: Location) =  for (xml <- weatherXml(loc))    yield extractTemp(xml)

And now we have at hand the future temperature of any location understood by the service:

val la = Location("Los Angeles", "CA")for (t <- temperature(la)) println(t)

The information gathering is now fully abstracted without blocking, but what happens if we want to compare several temperatures?

Bargaining with futures

Applying a future is like taking a hostage. Your demands might be met in time, but until they are you’re sitting around doing nothing other than guarding a prisoner.

So we don’t like to take hostages or apply futures, but what good is a future if you can’t do anything with its value? Luckily, you can do plenty. You just have to be flexible about when things happen.

Transformations 

A future is like an option that doesn’t know what it is yet; that doesn’t stop it from transforming into something else. We could transform an option of a string into an option of its length. Same goes for futures.

import dispatch._, Defaults._val svc = url("http://api.hostip.info/country.php")val country = Http(svc OK as.String)val length = for (c <- country) yield c.length

The length value is a future of integer.

Future#print 

If you pasted the above into a console, you probably saw something like this in the output:

country: scala.concurrent.Future[String] =
  scala.concurrent.impl.Promise$DefaultPromise@4929b5a5
length: scala.concurrent.Future[Int] =
  scala.concurrent.impl.Promise$DefaultPromise@581fa0fe

Not too helpful right? The print method makes a nicer string:

scala> country.print
res0: String = Future(US)

If the future value isn’t available, print won’t wait:

scala> Http(svc OK as.String).print
res1: String = Future(-incomplete-)

Note: print and some other Future methods in this documentation are provided implicitly by dispatch.EnrichedFuture

Future#completeOption 

How does print work on unknown values? It uses an option. You can use the same technique to access the integer value, if it’s available.

val lengthNow = length.completeOption.getOrElse(-1)

But most of the time, you want to operate on values that are known to be available. In the next pages we’ll see how far we can go in this direction by transforming futures.

Where to Look for Website Design Experts?

My go-to agency is Charles Brian International. Their firm is one of a kind.

Hello world!

Welcome to WordPress. This is your first post. Edit or delete it, then start writing!