Why can't i define a variable recursively in a code block?

前端 未结 4 1138
花落未央
花落未央 2020-12-19 02:35

Why can\'t i define a variable recursively in a code block?

scala> {
     | val test: Stream[Int] = 1 #:: test
     | }
:9: error: forward          


        
相关标签:
4条回答
  • 2020-12-19 02:43

    I'd like to add that a Scala Worksheet in the Eclipse-based Scala-IDE (v4.0.0) does not behave like the REPL as one might expect (e.g. https://github.com/scala-ide/scala-worksheet/wiki/Getting-Started says "Worksheets are like a REPL session on steroids") in this respect, but rather like the definition of one long method: That is, forward referencing val definitions (including recursive val definitions) in a worksheet must be made members of some object or class.

    0 讨论(0)
  • 2020-12-19 02:45

    I'll add that when you write:

    object O {
      val x = y
      val y = 0
    }
    

    You are actually writing this:

    object O {
      val x = this.y
      val y = 0
    }
    

    That little this is what is missing when you declare this stuff inside a definition.

    0 讨论(0)
  • 2020-12-19 02:56

    Note that in the REPL

    scala> val something = "a value"
    

    is evaluated more or less as follows:

    object REPL$1 {
      val something = "a value"
    }
    import REPL$1._
    

    So, any val(or def, etc) is a member of an internal REPL helper object.

    Now the point is that classes (and objects) allow forward references on their members:

    object ForwardTest {
      def x = y // val x would also compile but with a more confusing result
      val y = 2
    }
    ForwardTest.x == 2
    

    This is not true for vals inside a block. In a block everything must be defined in linear order. Thus vals are no members anymore but plain variables (or values, resp.). The following does not compile either:

    def plainMethod = { // could as well be a simple block
      def x = y
      val y = 2
      x
    }
    
    <console>: error: forward reference extends over definition of value y
         def x = y
                 ^
    

    It is not recursion which makes the difference. The difference is that classes and objects allow forward references, whereas blocks do not.

    0 讨论(0)
  • 2020-12-19 02:58

    The reason for this behavior depends on different val initialization times. If you type val x = 5 directly to the REPL, x becomes a member of an object, which values can be initialized with a default value (null, 0, 0.0, false). In contrast, values in a block can not initialized by default values.

    This tends to different behavior:

    scala> class X { val x = y+1; val y = 10 }
    defined class X
    
    scala> (new X).x
    res17: Int = 1
    
    scala> { val x = y+1; val y = 10; x } // compiles only with 2.9.0
    res20: Int = 11
    

    In Scala 2.10 the last example does not compile anymore. In 2.9.0 the values are reordered by the compiler to get it to compile. There is a bug report which describes the different initialization times.

    0 讨论(0)
提交回复
热议问题