Reputation: 1091
I'm a Java engineer who's been slowly learning Scala recently. I've come across some sample code using Dispatch to make a simple GET request:
val request = url("http://somesite.com")
val result = Http( request OK as.String)
The problem is... I don't quite get what's going on here. First, is Http a class? or a method? Second, what's up with the parameters passed to it? I thought maybe we were passing three arguments, with Scala allowing us to omit commas. But when I tried adding commas, I got a compilation error, so that can't be right.
I'm sure this makes sense to someone fluent in Scala, but I'm not there yet and it's holding me up. I've tried looking for documentation online, but have found nothing helpful.
Upvotes: 12
Views: 4495
Reputation: 139028
Here's a (painfully) explicit version with all the syntactic sugar taken out:
import dispatch.{ Defaults, Http, Req, as, implyRequestHandlerTuple, url }
import scala.concurrent.Future
val request: Req = url.apply("http://somesite.com")
val result: Future[String] =
Http.apply(
implyRequestHandlerTuple(request).OK[String](as.String)
)(Defaults.executor)
url
is a singleton object with an apply
method that returns an instance of the Req
case class. Http
is also a singleton object, and it also has an apply
method. Http
's apply
takes two parameter lists—the first taking a single Req
parameter, and the second taking an execution context (which you can think of as Scala's version of Java's Executor
).
implyRequestHandlerTuple
is an implicit method. Req
doesn't have an OK
method, but the compiler knows that the RequestHandlerTupleBuilder
class does (and that it takes the appropriate arguments—in this case a function from Response
to some type), so in the original version it automatically applies this method to make the conversion from Req
.
Finally, as
is a package that contains a String
singleton object. This object extends Response => String
(which is more syntactic sugar for Function1[Response, String]
. Our OK
method was looking for a function taking a Response
, so we're good there.
In the end you've got a Future[String]
. There are plenty of other places to read about futures, so I won't go into detail here, but in short this value can either be unsatisfied (i.e. you're still waiting for a result), or satisfied with a failure (in case of network error, etc.), or satisfied successfully (in which case it'll contain the response body).
Upvotes: 26
Reputation: 55569
url
is (essentially) a method that returns a Req
object. So request
has type Req
.
Http
is a class with a companion object that has a few overloads of the apply
method. So when you see:
Http(request OK as.String)
It is actually syntactic sugar for:
Http.apply(request OK as.String)
Ok, so what's going on inside apply
? It appears as though a method named OK
is being called on request
. But looking through the API Docs, you may notice there is no such method OK
for the type Req
. There is, however, a class called RequestHandlerTupleBuilder
, which does have such a method. And there is an implicit conversion defined in the dispatch
package:
implicit def implyRequestHandlerTuple(builder: Req) =
new RequestHandlerTupleBuilder(builder)
What's happening here is that when you call request OK
, the compiler sees that request
does not have an OK
method. So it then looks for possible implicit methods that accept Req
as a parameter and return types to do have such a method. The above method is the implicit it finds, so the Req
is implicitly converted to a RequestHandlerTupleBuilder
.
Now let's look at the signature of OK
:
def OK [T](f: Response => T): (Request, OkFunctionHandler[T])
It accepts a function as a parameter. In particular, a function that accepts a Response
as a parameter, and returns some other type T
. In this case, such a function is as.String
that has type Response => String
. OK
will then return a Request
tupled with an OkFunctionHandler[T]
.
This tells me that the overload of apply
we're calling is this one:
def apply[T](pair: (Request, AsyncHandler[T])): Future[T]
(OkFunctionHandler
extends AsyncHandler
)
Looking it all in a slightly more java-like style and with type annotations, you have:
val request: Req = url("http://somesite.com")
val result: Future[String] = Http.apply(request.OK(as.String))
Using only explicit calls, it would look more like:
val result: Future[String] =
Http.apply(implyRequestHandlerTuple(request).OK(as.String))
In short, there is only one parameter being passed to Http.apply
, it's just using a point-free style to call other methods within.
Upvotes: 9