How to interpret function value wrapped in curly braces (ammonite issue)

86 Views Asked by At

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.

1

There are 1 best solutions below

2
Mateusz Kubuszok On BEST ANSWER

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.