score:2

Accepted answer

Does it mean that blocks are objects too?

No, blocks are not objects. Blocks are used for scoping the binding of variables. Scala enables not only defining expressions inside blocks but also to define methods. If we take your example and compile it, we can see what the compiler does:

object Test extends Object {
  def method1(): Unit = scala.Predef.println("method 1");

  private[this] val x: String = _;
  <stable> <accessor> def x(): String = Test.this.x;

  final <static> private[this] def method2$1(): String = "method 2";

  def <init>(): tests.Test.type = {
    Test.super.<init>();
    Test.this.x = {
      "this is ".+(Test.this.method2$1())
    };
    Test.this.method1();
    scala.Predef.println(Test.this.x());
    ()
  }
}

What the compiler did is extract method2 to an "unnamed" method on method2$1 and scoped it to private[this] which is scoped to the current instance of the type.

And how are handled the statements part of an object, are they members too?

The compiler took method1 and println and calls them inside the constructor when the type is initialized. So you can see val x and the rest of the method calls are invoked at construction time.

score:1

method2 is actually not a method. It is a local function. Scala allows you to create named functions inside local scopes for organizing your code into functions without polluting the namespace.

It is most often used to define local tail-recursive helper functions. Often, when making a function tail-recursive, you need to add an additional parameter to carry the "state" on the call stack, but this additional parameter is a private internal implementation detail and shouldn't be exposed to clients. In languages without local functions, you would make this a private helper alongside the primary method, but then it would still be within the namespace of the class and callable by all other methods of the class, when it is really only useful for that particular method. So, in Scala, you can instead define it locally inside the method:

// non tail-recursive
def length[A](ls: List[A]) = ls match {
  case Nil => 0
  case x :: xs => length(xs) + 1
}

//transformation to tail-recursive, Java-style:
def length[A](ls: List[A]) = lengthRec(ls, 0)

private def lengthRec[A](ls: List[A], len: Int) = ls match {
  case Nil => len
  case x :: xs => lengthRec(xs, len + 1)
}

//tail-recursive, Scala-style:
def length[A](ls: List[A]) = {
  //note: lengthRec is nested and thus can access `ls`, there is no need to pass it
  def lengthRec(len: Int) = ls match {
    case Nil => len
    case x :: xs => lengthRec(xs, len + 1)
  }

  lengthRec(ls, 0)
}

Now you might say, well I see the value in defining local functions inside methods, but what's the value in being able to define local functions in blocks? Scala tries to as simple as possible and have as few corner cases as possible. If you can define local functions inside methods, and local functions inside local functions … then why not simplify that rule and just say that local functions behave just like local fields, you can simply define them in any block scope. Then you don't need different scope rules for local fields and local functions, and you have simplified the language.

The other thing you mentioned, being able to execute code in the bode of a template, that's actually the primary constructor (so to speak … it's technically more like an initializer). Remember: the primary constructor's signature is defined with parentheses after the class name … but where would you put the code for the constructor then? Well, you put it in the body of the class!


Related Query

More Query from same tag