4

I'm working through ScalaInAction (book is still a MEAP, but code is public on github) Right now I'm in chapter 2 looking at this restClient: : https://github.com/nraychaudhuri/scalainaction/blob/master/chap02/RestClient.scala

First, I setup intelliJ with scala extensions and created a HelloWorld with main():

<ALL the imports>

object HelloWorld {
   def main(args: Array[String]) {
     <ALL the rest code from RestClient.scala>
   }
}

I get the following error when compiling:

scala: forward reference extends over defintion of value command
val httppost = new HttpPost(url)
                ^

I can fix this by moving the following lines around until the ordering is correct with relation to the def's

require( args.size >= 2, "You need at least two arguments to make a get, post, or delete request")

val command = args.head
val params = parseArgs(args)
val url = args.last

command match {
  case "post"    => handlePostRequest
  case "get"     => handleGetRequest
  case "delete"  => handleDeleteRequest
  case "options" => handleOptionsRequest
}

While browsing the github page, I found this: https://github.com/nraychaudhuri/scalainaction/tree/master/chap02/restclient

Which uses implements RestClient.scala using extends App instead of a main() method:

<All the imports>
object RestClient extends App {
   <All the rest of the code from RestClient.scala>
}

I then changed my object HelloWorld to just use extends App instead of implementing a main() method and it works without errors

Why does the main() method way of doing this generate the error but the extends App does not?

TheBigS
  • 491
  • 1
  • 4
  • 14
  • @om-nom-nom While that is a duplicate of the title, it's not a duplicate of the described issue :( –  Jan 27 '13 at 23:23
  • @pst well, the answer has mentioned [delayed init](http://www.scala-lang.org/archives/downloads/distrib/files/nightly/docs/library/index.html#scala.DelayedInit) which is a key for understanding shown behaviour. – om-nom-nom Jan 27 '13 at 23:24
  • @om-nom-nom I still don't get it, Can you explain why delay init resolves the error but `main()` doesn't? – TheBigS Jan 27 '13 at 23:27
  • 1
    I would say it is a duplicate of [Scala: forward references - why does this code compile?](http://stackoverflow.com/questions/7762838/scala-forward-references-why-does-this-code-compile). Delayed init is not the issue here – kiritsuku Jan 27 '13 at 23:27
  • @sschaef Ah Thanks, I think that clears it up. So just to make sure I understand this correctly, the main() method version is executing the instructions of `main()` in sequence (as it should) and the `val`'s aren't declared till the end of method, so the earlier `def`s cause the `forward references` error. But in the `extends App` usage, the declarations and the construction are split so the `val`s are declared before the `def`s and all is good. – TheBigS Jan 27 '13 at 23:42

1 Answers1

6

Because main() is a method, and variable's in method could not be forward reference.

For example:

object Test {

   // x, y is object's instance variable, it could be forward referenced

   def sum = x + y // This is ok
   val y = 10    
   val x = 10

}

But code in a method could not forward referenced.

object Test {
    def sum = {
        val t = x + y // This is not ok, you don't have x, y at this point
        val x = 10
        val y = 20
        val z = x + y // This is ok
    }
}

In your case, if you copy paste all codes from RestClient.scala to main(), you will have the same issue because var url is declared after its usage in handlePostRequest.

Brian Hsu
  • 8,781
  • 3
  • 47
  • 59