Why does the Scala 2.11.0-M3
compiler give me error: identifier expected but integer literal found.
when the round brackets ()
are use
When you write
{ i: Int => 2 * i }
the braces are a block, and the thing inside is the result expression of the block.
The syntax is the ResultExpr here. Note that a type is allowed after the param name, as above.
That's different from an Expr where it is not.
Here's an example of the difference:
scala> val is = List(1,2,3)
is: List[Int] = List(1, 2, 3)
The first statement in block has a function literal, an Expr requiring parens if we specify the type. The last statement is the result expression of the block, and no parens are required:
scala> is map { val f = (i: Int) => 2*i; i: Int => 2*f(i) }
res0: List[Int] = List(4, 8, 12)
Sometimes you don't need to specify the type because it is inferred from the expected type, and with no type in the Expr, you can omit the parens:
scala> is map { val f: Int=>Int = i => 2*i; i: Int => 2*f(i) }
The Bindings in these productions (in the spec) is your ordinary list of params in parens, which maybe have types. With more than one param, you have to supply parens:
scala> is reduce { val f = (i:Int,j:Int) => i+j; (i:Int,j:Int) => 2*f(i,j) }
res2: Int = 18
Sometimes you'll see a big block of code as an argument to a function. That's a big function literal as the result expression of a block, which is why you see the parameter sitting out in front, with no parens or braces:
scala> is map { i => val j = 2 * i; /* lots of LOC */ ; j }
res7: List[Int] = List(2, 4, 6)
That is different from the following code, which is block of many lines of code with the function literal at the very end. The function just returns j
, or 2:
scala> is map { val j = 2; /* lots of LOC */ ; _ => j }
res8: List[Int] = List(2, 2, 2)
So we know that you can't write the following:
scala> is map (is: Int => 2)
<console>:1: error: identifier expected but integer literal found.
is map (is: Int => 2)
^
What sort of identifier would be meaningful in this context? How about:
scala> is map (is: Int => Int)
which yields the delightful result (spoiler alert):
java.lang.IndexOutOfBoundsException: 3
This works:
scala> val js = List(0,1,2)
js: List[Int] = List(0, 1, 2)
scala> js map (js: Int => Int)
res0: List[Int] = List(0, 1, 2)
The js
in parens is just a value, obviously, not a param, and the type is a type ascription. The value can be a post-fix expression, so this works (or rather, compiles with a feature warning about the post-fix operator syntax):
scala> js map (js init: Int => Int)
warning: there were 1 feature warning(s); re-run with -feature for details
java.lang.IndexOutOfBoundsException: 2
More explanation at this answer:
https://stackoverflow.com/a/13873899/1296806
There is a category of confusion caused by thinking that parens and curly braces are somehow exchangeable. But I found it clarifying to see braces as BlockExprs
, which is what they are. Then it's easier to remember, for instance, that when you use braces in a function application, there is no magic: you've simply supplied a block.
A block is a bunch of side-effecting statements followed by a result statement. That's obvious for functional programmers, perhaps. But it clarifies that the last thing in your braces is a ResultExpr
.
(Footnote: braces for class bodies are different, of course.)
I've digged into The Scala Language Specification for Scala 2.9, and found out that part 6.23 describes how anonymous function have to be defined:
Expr ::= (Bindings | [‘implicit’] id | ‘_’) ‘=>’ Expr
ResultExpr ::= (Bindings | ([‘implicit’] id | ‘_’) ‘:’ CompoundType) ‘=>’ Block
Bindings ::= ‘(’ Binding {‘,’ Binding} ‘)’
Binding ::= (id | ‘_’) [‘:’ Type]
As you can see Bindings
requires to be placed inside two surrounding parenthesis. So if your anonymous function defines the type of the parameter, it has to be defined in this way:
(c:Char) => 1
And the call to map should look like that:
s.toList map((c:Char) => 1)
Also in the same part of reference documentation you can find:
If an anonymous function (x: T) => e with a single typed parameter appears as the result expression of a block, it can be abbreviated to x: T => e.
So it says that if anonymous function is defied as last expression in a code block, and has exacly one parameter, you can use abbreviated syntax to define anonymous function - without parenthesis. So, in your case, you can write c:Char => 1
but only when you place it inside a code block {c:Char => 1}
. And you can call map function this way:
s.toList map({c:Char => 1})
or with abbreviated syntax without parenthesis:
s.toList map {c:Char => 1}
On the other hand, when we look back at the anonymous function specification:
Expr ::= (Bindings | [‘implicit’] id | ‘_’) ‘=>’ Expr
We can see that we can define your anonymous function, if we don't want to specify argument type, without parameter binding in those two ways:
s.toList map (c => 1)
// or
s.toList map (_ => 1)
Also, this is summarized in changelog at the end of the documentation (Changes in Version 2.1.7 (19-Jul-2006)):
Closure Syntax
The syntax of closures has been slightly restricted (§6.23). The form
x: T => E
is valid only when enclosed in braces, i.e.
{ x: T => E }
. The following is illegal, because it might be read as the value x typed with the type T => E:
val f = x: T => E
Legal alternatives are:
val f = { x: T => E }
val f = (x: T) => E
When you write an expression c:Char => 1
, Scala compiler treats it as c:(Char => 1)
, that is, a function variable c
with type Char => 1
. However, 1
is not a valid type (or type variable), so Scala compiler complains. So you need to write s.toList map ((c:Char) => 1)
to help the compiler out of the type association.
{c:Char => 1}
creates a function literal, that is, a function that accepts a char and returns 1. So
s.toList map {c:Char => 1}
is the same as
s.toList map({c:Char => 1})
// or
val fn = {c: Char => 1}
s.toList map fn
However, it seems that Scala doesn't have special specification for the {c:Char => blabla}
form for creating function literals.
I think it is because that there is {some_var: SomeType => *Class Definition* }
form in class definition to reference this
with some_var
and add lower bound of the type of this
. This causes the Scala lexer to treat a single typed parameter after {
to be formal parameter and treat the statements after =>
to be actual body. Note that you CANNOT create a function with 2 parameters like this {c: Char, d:Char => 1}
.
UPDATE: As commented by som-snytt, it is result expression that causes the brace version to be evaluated to a function result.