6

After reading What is the formal difference in Scala between braces and parentheses, and when should they be used?, I still don't know how to understand function value wrapped in {}.

Consider the following two REPL sessions:

@ val f = { (x: Int) =>
    x
    val y = x
    y
  }
f: Int => Int = ammonite.$sess.cmd30$$$Lambda$1765/0x0000000801346840@24c7b944
@ { (x: Int) =>
    x
    val y = x
    y
  }
cmd31.sc:3: not found: value x
  val y = x
          ^
Compilation Failed

I have several questions.

  1. Why the first snippet compiles while the second doesn't? In the first snippet, compiler knows the {...} as a whole is a function value. In the second snippet, only the (x: Int) => \n x part is function value (Sorry about the \n to indicate line break). Why?
  2. Regarding the { (x: Int) => \n ... }, when is it interpreted as function value and when is it not?
  3. Is the curly brace ({}) part of the function value, or only (...) => ... inside is function value? If it is a part it, does the form have a name? For example, I think (_ + _) could be called function value's placeholder syntax.

Update: This is purely an Ammonite issue. See answer for detail.

Naitree
  • 1,088
  • 1
  • 14
  • 23

1 Answers1

4

The problem here is ammonite.

Scala REPL has a paste mode allowing you to paste multiple lines before evaluating:

:paste
sealed trait X
class Implementation extends X // impossible without doing it at once
// Ctrl+D

Ammonite doesn't have such paste mode, but it allows you to perform multi-line copy paste... but wrapping them all in {} which ammonite would unwrap. So your code:

{ (x: Int) =>
  x
  val y = x
  y
}

is seen by compiler as

(x: Int) =>
  x // end of function definition
val y = x // new variable calling x, which isn't defined anywhere
y // call to undefined y, because previous line failed

The first example works because you have val f = so ammonite's parser cannot assume that all of your code is within one block, so it doesn't strip it before passing it into compiler.

As docs suggest if you don't want this behavior you should add another layer of curly brackets:

{{ (x: Int) =>
  x
  val y = x
  y
}}

This isn't a compiler and language specification issue as much as issue with some particular REPL implementation.

Mateusz Kubuszok
  • 24,995
  • 4
  • 42
  • 64
  • 3
    Oh my... 1 hour wasted by ammonite... Thank you for helping me out. (Ok, Shouldn't blame ammonite. Just read the doc...) – Naitree Jun 24 '20 at 09:40
  • 1
    No problem, I think I got burned by this as well, this is quite convenient if you know about it (more than writing `:paste` and then closing it with Ctrl+D) but if you aren't aware it's an annoying pitfall. – Mateusz Kubuszok Jun 24 '20 at 09:53