1

In Scala, if you have an expression containing an underscore, this is an anonymous function with the expression as its body and the underscore as as its parameter, e.g. 2*_ is the anonymous function that doubles its argument. But how far does the function body extend? I'm missing a clear rule here that disambiguates cases like e.g. the following (tested with the Scala 2.11.7 REPL):

scala> (_: Int)+2-1  // function body up to 1 - OK
res7: Int => Int = <function1>

scala> ((_: Int)+2)-1  // function body up to 2, - applied to function is an error
<console>:11: error: value - is not a member of Int => Int
   ((_: Int)+2)-1
               ^
Holger Peine
  • 1,079
  • 1
  • 9
  • 13
  • 3
    While the question is not a duplicate, the accepted answer of the question can be applied directly to this question: http://stackoverflow.com/questions/2173373/scala-foreach-strange-behaviour – kiritsuku Dec 27 '15 at 11:43
  • Yes, the question you cite does answer my question by saying "... the rules of expansion of _. It expands to the innermost expression delimiter (parenthesis or curly braces)". I can only hope, however, that this quote really contains the whole story, since I am not perfectly sure if this quote is equivalent to the spec's statement "(2)" as quoted by Alexey Romanov below (see my comment there). That said, I would accept your answer as (hopefully!) correct if it were possible to accept a comment ;-) – Holger Peine Dec 28 '15 at 11:32
  • Some cases where you need to be careful with this definition: 1. It can extend farther than the nearest parentheses/curly braces: `foo(1, _)`, but in this case they don't delimit an `Expr`. 2. In `foo(_)` the parentheses _do_ delimit an `Expr`, but it consists only of the underscore section itself and you need to look outside. 3. `=`, `=>`, `;`, newline, and the keywords you can see around `Expr` in the grammar can also serve as expression delimiters. – Alexey Romanov Dec 28 '15 at 12:53
  • Ah - your item 3 now resolves my feeling that "outwards until brace/paren" was not a complete solution. Now I'm confident that "outwards until brace, paren,=, => ; newline and the other keywords" is the rule that I should memorize - thanks once more! – Holger Peine Dec 28 '15 at 15:52

2 Answers2

1

The definition is given in http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#placeholder-syntax-for-anonymous-functions, and it's... not that simple.

An expression e of syntactic category Expr binds an underscore section u, if the following two conditions hold: (1) e properly contains u, and (2) there is no other expression of syntactic category Expr which is properly contained in e and which itself properly contains u.

If an expression e binds underscore sections u_1 , \ldots , u_n, in this order, it is equivalent to the anonymous function (u'_1, ... u'_n) => e' where each u_i' results from u_i by replacing the underscore with a fresh identifier and e' results from e by replacing each underscore section u_i by u_i'.

And if you look at the grammar in the beginning of the section, (_: Int)+2 in (_: Int)+2-1 is not an Expr, but in ((_: Int)+2)-1 it is.

Community
  • 1
  • 1
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • OK, from building a parse tree (on paper), I can see that (_: Int)+2 parses as an InfixExpr (but not a more general expression such as Expr) when embedded within (_: Int)+2+1 because only then it can be combined with - 1 to form another (higher-level) InfixExpr. So, it does not fulfill requirement (2) of the spec, because it is not of category Expr. In contrast to that, (_: Int)+2 parses also as PostfixExpr, Expr1 and Expr when embedded in parens as in ((_: Int)+2)-1. To avoid that analysis every time I use _, I'll stick to the "outwards until brace/paren" rule from question cited above. – Holger Peine Dec 28 '15 at 11:47
0
((_: Int)+2)-1  // function body up to 2, - applied to function is an error 

error: value - is not a member of Int => Int
   ((_: Int)+2)-1

The error message from the compiler is sensible. Your additional parens have created a function literal that adds '2' to a wildcard/placeholder parameter. The compiler reads your code to mean that you have a this function value and you are trying to subtract '1' from it.

And this doesn't make sense. You can subract '1' from other numbers, but certainly not a function value. Thus, the compiler is telling you that it doesn't make sense to subtract one from a function value. Or, in compiler terms, a function of type Int => Int doesn't have a '-' function.

value - is not a member of Int => Int

Understanding this error message requires that you know that all operators in Scala ( -, *, +, etc ) are implemented as methods of types. If you look at the Scala API docs for Int, you'll see that it defines a long list of methods with common mathematical and logical operator symbols as function names.

chad
  • 7,369
  • 6
  • 37
  • 56
  • chad, while your explanation of the error message is correct, that was not my question (I was aware of this, as my source code comment "applied to function" shows). Instead, I wanted an explanation how much of an expression containing an underscore will be used as the function body (and not an explanation of why an erroneous conception of the size of the function body will produce a compiler error). Never mind, however - your answer may be useful to other readers anyway. – Holger Peine Dec 28 '15 at 11:08