Single statement as expression


#1

I created a method which need By-name parameters

  def twice(action: => Unit) = {
    action
    action
  }
twice(System.out.println("bar"))

compiles,but the following one dosen’t

  twice(
    System.out.println("bar")
    System.out.println("foo")
  )

In this case I need to add curly braces to make it statement

  twice {
    System.out.println("bar")
    System.out.println("foo")
  }

So is a single System.out.println("bar") a statement?
Why twice(System.out.println("bar")) compiles?


#2

More precisely, you need to wrap the two expressions in curly braces to forge them into a single block expression - see the language spec, in particular §6, §6.11, §6.25. The first is parsed as a block statement, the second as a result expression.

The key takeaway is that the more important concept here is expressions. Statements are required to account for imports and definitions/templates, but these don’t occur in this example at all. Where statements are used, they are just a step on the way to arrive at a proper expression in the end.

Theoretically you could use mechanisms other than a block to combine the two (side-effecting) expressions into one - silly example:

def chain[A, B](a: => A)(b: => B): B = ((x: A) => b)(a)

twice(chain(System.out.println("bar"))(System.out.println("foo")))

#3

The error message is revealing:

error: value println is not a member of Unit
possible cause: maybe a semicolon is missing before `value println’?

This:

twice(
System.out.println(“bar”)
System.out.println(“foo”)
)

parses as

twice(System.out.println(“bar”).println(“foo”))

while this:

twice {
System.out.println(“bar”)
System.out.println(“foo”)
}

parses as:

twice({ System.out.println(“bar”); System.out.println(“foo”) })