5

I have the following Scala/Play! code:

case class Tweet(from: String, text: String)

implicit val tweetReads = (
 (JsPath \ "from_user_name").read[String] ~
 (JsPath \ "text").read[String]) (Tweet.apply _)

I have several questions regarding the syntax and meaning of the above code:

  • On what class/object is the ~ method invoked on?
  • What is the class/type of the argument to Tweet.apply?

edit 1: full source code:

package models

import play.api.libs.json._
import play.api.libs.json.util._
import play.api.libs.json.Reads._
import play.api.libs.json.Writes._
import play.api.libs.functional.syntax._

case class Tweet(from: String, text: String)

object Tweet {

  implicit val tweetReads = (
      (JsPath \ "from_user_name").read[String] ~
      (JsPath \ "text").read[String])(Tweet.apply _)

  implicit val tweetWrites = (
    (JsPath \ "from").write[String] ~
    (JsPath \ "text").write[String])(unlift(Tweet.unapply))
}
balteo
  • 23,602
  • 63
  • 219
  • 412

2 Answers2

8

Step by step:

Method \ on object JsPath

val path1: JsPath = JsPath \ "from_user_name"
val path2: JsPath = JsPath \ "text"

Method read on object of type JsPath

val reads1: Reads[String] = path1.read[String]
val reads2: Reads[String] = path2.read[String]

There is no method ~ in Reads, but there is such method in FunctionalBuilderOps and there is an implicit conversion from M[T] to FunctionalBuilderOps[M[_], T] in play.api.libs.functional.syntax - toFunctionalBuilderOps.

val reads1FunctionalBuilderOps: FunctionalBuilderOps[Reads, String] =
  toFunctionalBuilderOps(reads1)

val canBuild2: CanBuild2[String, String] = reads1FunctionalBuilderOps.~(reads2)

Tweet.apply _ is a scala syntax to create a FunctionN using method with N arguments:

val func: (String, String) => Tweet = Tweet.apply _

There is an apply method in CanBuild2[A, B]. It accepts (A, B) => C and returns Reads[C] (in this case):

implicit val tweetReads: Reads[Tweet] = canBuild2.apply(func)

Actually there are also implicit parameters in JsPath#read, toFunctionalBuilderOps and CanBuild2#apply methods. With that parameters:

val reads1: Reads[String] = path1.read[String](Reads.StringReads)

...
val reads1FunctionalBuilderOps: FunctionalBuilderOps[Reads, String] =
  toFunctionalBuilderOps(reads1)(
    functionalCanBuildApplicative(
      Reads.applicative(JsResult.applicativeJsResult)))

...
implicit val tweetReads: Reads[Tweet] =
  canBuild2.apply(func)(functorReads)
senia
  • 37,745
  • 4
  • 88
  • 129
  • Hi Senia! Thanks for this detailed reply. I am in the process of studying your reply. I will come up with questions. Bear with me... – balteo Jan 08 '14 at 09:42
  • Can you please confirm that `Tweet.apply _` is an invocation of apply? Also what is the `_` placeholder standing for? – balteo Jan 08 '14 at 11:40
  • I am confused with this `Tweet.apply _`... Why is there only one argument to apply (i.e. _)? – balteo Jan 08 '14 at 11:43
  • 1
    @balteo: here `Tweet.apply _` is special syntax for something like `(a, b) => Tweet.apply(a, b)`. You need a function of type `(A1, A2, ... AN) => R` and you have a method `(A1, A2, ... AN)R`. `method _` is a syntax to create new function (object of type `FunctionN`) using method. – senia Jan 08 '14 at 11:44
  • 1
    @balteo: it's not `one argument`. `Tweet.apply(_)` means `one argument`, but `Tweet.apply _` means `all arguments`. – senia Jan 08 '14 at 11:45
  • Thanks.... I am also looking for official documentation/references about `val func: (String, String) => Tweet = Tweet.apply _` I cannot seem to find anything about this construct/syntax in my books. Can you please kindly provide a link? – balteo Jan 08 '14 at 11:57
  • Also in `Tweet.apply _`, how is **this** specific usage of the underscore called in scala parlance? – balteo Jan 08 '14 at 12:24
  • 1
    @balteo: see [The Scala Language Specification](http://www.scala-lang.org/docu/files/ScalaReference.pdf) **6.7 Method Values**. – senia Jan 08 '14 at 12:50
  • @balteo: See also [What are all the uses of an underscore in Scala?](http://stackoverflow.com/questions/8000903/what-are-all-the-uses-of-an-underscore-in-scala) – senia Jan 08 '14 at 12:56
  • In this line https://github.com/playframework/playframework/blob/9206bea8c9c88acdc6786ebb2554f081396e8f6a/framework/src/play-functional/src/main/scala/play/api/libs/functional/syntax/package.scala#L21, from where does the first `implicit` (fcb) argument come? `implicit def toFunctionalBuilderOps[M[_], A](a: M[A])(implicit fcb: FunctionalCanBuild[M]) ...` – Kevin Meredith Feb 24 '14 at 14:16
  • @KevinMeredith: [next method (line 23)](https://github.com/playframework/playframework/blob/9206bea8c9c88acdc6786ebb2554f081396e8f6a/framework/src/play-functional/src/main/scala/play/api/libs/functional/syntax/package.scala#L23) – senia Feb 24 '14 at 14:47
  • Ah, so you knew that `OFormat[A]` is-a `Applicative[A]`? Or you used `REPL` to identify the implicit? – Kevin Meredith Feb 24 '14 at 15:04
  • @KevinMeredith: there is only 5 imports in question, so one can find all implicits in that imports and companion objects. I don't need REPL for this. But with `reify` one can get all implicits in REPL. – senia Feb 24 '14 at 15:12
  • @senia, thanks. So for `Format.scala`, you know that line 20 (https://github.com/playframework/playframework/blob/9206bea8c9c88acdc6786ebb2554f081396e8f6a/framework/src/play-json/src/main/scala/play/api/libs/json/Format.scala?source=cc#L20) resolves its `rcb` and `wcb` by looking at the implicits in line 18(https://github.com/playframework/playframework/blob/9206bea8c9c88acdc6786ebb2554f081396e8f6a/framework/src/play-json/src/main/scala/play/api/libs/json/Format.scala?source=cc#L18)? – Kevin Meredith Feb 24 '14 at 15:44
2

I would just add that this is called applicative syntax (for applicative functors). It can be seen for example in scala parser combinator library

If you want to know how to use it with json try to read this. Another example of applicative functors in play framework is form handling. Or you can try to read about scalaz Validation.

Martin Kolinek
  • 2,010
  • 14
  • 16