This question already has answers here:
What is the formal difference in Scala between braces and parentheses, and when should they be used?
(9 answers)
Closed 9 years ago.
I am a little confused by the various uses of the 'block' {...} contruct in scala especially when calling a higher order function like in the following example.
def higherOrder(func: Int => Int): Int = {
func(4)
}
val f = ((x: Int) => x*x)
Then I can call higherOrder like so:
higherOrder(f), or
higherOrder {f}, or
higherOrder { x => x*x }
(1) is obvious,
but I can not wrap my head around how the syntax for (2) and (3) are parsed by the compiler
Can somebody explain what (2) and (3) correspond to, with regard to the language specification?
See SLS 6.6 Function Applications. Function application is defined like this:
SimpleExpr ::= SimpleExpr1 ArgumentExprs
ArgumentExprs ::= ‘(’ [Exprs] ‘)’
...
| [nl] BlockExpr
And BlockExpr is
BlockExpr ::= ‘{’ CaseClauses ‘}’
| ‘{’ Block ‘}’
So after function or method name you could specify either arguments list in brackets or expression in braces.
Related
Is there a way to create a function that can be passed additional parameters in infix notation in scala?
Something like this: a op(additionalParam) b
Edit: I'm pretty sure this is not possible. Maybe someone can convince me otherwise? In the end I just need to pass a number to op
No, the language specification has this:
InfixExpr ::= PrefixExpr
| InfixExpr id [nl] InfixExpr
PrefixExpr ::= [‘-’ | ‘+’ | ‘!’ | ‘~’] SimpleExpr
So infix only works with a simple id between two expressions. The id is the name of a method on the object returned by the first expression that takes an argument compatible with the type of the second expression.
I don't think so, but you might do something like this.
class A {
def op(b: B): C = new C
def op(otherParam: OP): A = new A
}
import scala.language.postfixOps
a op b //->C
a op addedParam op b //->C
Just replace the A, B, C, and OP types with something more meaningful.
I found that parentheses are not required when partial function used as parameter in Scala
val array = Array(2)
array.map(x => x + 1)
array.map { case x => x + 1 }
{ case x => x + 1 } defines a partial function here, so it should be array.map({ case x => x + 1 }), but there are no parentheses.So what happend here? what syntactic is here?
The answer is in the language specification. The syntax for function applications is this:
SimpleExpr ::= SimpleExpr1 ArgumentExprs
ArgumentExprs ::= ‘(’ [Exprs] ‘)’
| ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ‘)’
| [nl] BlockExpr
Exprs ::= Expr {‘,’ Expr}
So the arguments to a function can be one or more expressions surrounded by ( ), or a single BlockExpr if the function takes a single argument.
Moving on the section about blocks we find this:
BlockExpr ::= ‘{’ CaseClauses ‘}’
| ‘{’ Block ‘}’
Block ::= BlockStat {semi BlockStat} [ResultExpr]
Partial functions are defined using the CaseClauses option, so they must be surrounded by { } to make a block expression. This block expression is then a valid argument for a function with a single parameter.
Functions that take multiple parameters must always use ( ).
The scala coding standards state that
Technically, Scala’s parser does support GNU-style notation with opening braces on the line following the declaration. However, the parser is not terribly predictable when dealing with this style due to the way in which semi-colon inference is implemented. Many headaches will be saved by simply following the curly brace convention demonstrated above.
I've looked, and I couldn't find any real examples of this. Can anyone explain the reasoning behind this with an exmaple? Has anyone run into problems with using curly braces on a new line?
Consider this expression:
someElement
{
// Some code
}
How is this interpreted? Is it an expression (such as a value, or a function call with no arguments) followed by a block statement enclosed within braces? Or is it a function call with the braces enclosing a single argument?
If Scala didn't have semicolon inference—that is, if Scala required semicolons to denote the end of a statement in the same manner that Java does—then the two could be easily distinguished because the former would require a semicolon at the end of the first line. However, the Scala parser has to infer where the semicolon(s) need to be to make sense of the code, and sometimes it gets things wrong. (Both interpretations, depending upon context, are valid and it's not always possible for the Scala parser to resolve the ambiguity by itself.)
For example, let's say that someElement is a function with a by name argument. If you attempt to call it in the Scala REPL intending to put the argument (within braces) on another line, you'll find that entering someElement alone causes an error:
> scala
Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_161).
Type in expressions for evaluation. Or try :help.
scala> def someElement(x: => Int): Int = {
| // Do something...
| x
| }
someElement: (x: => Int)Int
scala> someElement
<console>:13: error: missing argument list for method someElement
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `someElement _` or `someElement(_)` instead of `someElement`.
someElement
^
That is, you don't even get as far as entering the braces. However, if you enter the following, then you're OK:
scala> someElement {
| 10
| }
res0: Int = 10
But what if someElement is a value? Now we see this in the REPL:
scala> val someElement = 5
someElement: Int = 5
scala> someElement
res1: Int = 5
scala> {
| 5
| }
res2: Int = 5
Now the REPL accepts the same code, on separate lines, as two different expressions.
Let's get really ambiguous. Say someElement is a value, but it's now a reference to a function taking a single argument. Let's look at the possible interpretations:
scala> def square(a: Int) = a * a
square: (a: Int)Int
scala> val someElement = square _
someElement: Int => Int = $$Lambda$1034/1609754699#74abbb
scala> someElement
res3: Int => Int = $$Lambda$1034/1609754699#74abbb
scala> {
| 5
| }
res4: Int = 5
That is, it's treated as two separate statements: a value followed by a block statement. However:
scala> someElement {
| 5
| }
res5: Int = 25
is treated as a call to square with an argument of 5.
The Scala compiler is a little smarter than the REPL since it can see all of the code at once, and will try to resolve ambiguities by seeing which of the alternatives make the most sense, but its interpretation may not always match yours.
So, as you can see, putting the open brace on the same line—if the two expressions are linked—makes the relationship explicit and removes ambiguity. Alternatively, if you want the expressions to be parsed unambiguously as separate statements, add a semicolon after the first line.
(IMHO, the semicolon inference is one of Scala's Achilles Heels.)
I was working on a project last night, and had some code like this:
/* fixes warnings in 2.10 */
import scala.language.implicitConversions
/* had some kind of case class with some members */
case class Wrapper[A](x: A)
/* for convenience's sake */
implicit def aToWrapper[A](x: A) = Wrapper(x)
/* had some kind of Seq */
val xs: List[Wrapper[String]] = List("hello", "world", "this", "is", "a", "test")
I then accidentally wrote:
xs foldLeft("") { (a, x) => a + x }
having left the . out between xs and foldLeft.
The types in question were a little more complex, and it asked me to annotate the lambda's parameter types, so I quickly did, thinking that was the source of my mistake. I ended up with something like this:
xs foldLeft("") { (a: String, x: Wrapper[String]) => a + x }
At this point I was receiving the error:
<console>:13: error: type mismatch;
found : (String, Wrapper[String]) => String
required: Int
xs foldLeft("") { (a: String, x: Wrapper[String]) => a + x }
^
Obviously the fix was xs.foldLeft("") ..., but I have been wondering why the compiler is expecting an Int in this case. Could anyone illuminate how this is being parsed? this has been nagging me all day.
When you leave out the dot and the parentheses you use the so called infix notation. It allows you to write a + b instead of a.+(b). An important rule here is that this is only allowed if a call is of the form object method paramlist (see SLS 6.12.3):
The right-hand operand of a left-associative operator may consist of several arguments enclosed in parentheses, e.g. e op (e 1 , ... , e n ). This expression is then interpreted as e.op(e 1 , ... , e n ).
foldLeft doesn't fit into this form, it uses object method paramlist1 paramlist2. Thus if you write this in operator notation the compiler treats it as object.method(paramlist1).paramlist2 (as described in SLS 6.12.2):
A postfix operator can be an arbitrary identifier. The postfix operation e op is interpreted as e.op.
But there is another rule applied here: Function Applications (SLS 6.6).
An application f(e 1 , ... , e m) applies the function f to the argument expressions
e 1 , ... , e m.
[...]
If f has some value type, the application is taken to be equivalent to f.apply(e 1 , ... , e m), i.e. the application of an apply method defined by f.
Here we go:
scala> { (a, x) => a + x }
<console>:12: error: missing parameter type
{ (a, x) => a + x }
^
<console>:12: error: missing parameter type
{ (a, x) => a + x }
^
This is just a function literals that misses its type arguments. If we add them everything compiles fine:
scala> { (a: String, x: Wrapper[String]) => a + x }
res6: (String, Wrapper[String]) => String = <function2>
The compiler just applies the rule about function applications described above:
scala> "" { (a: String, x: Wrapper[String]) => a + x }
<console>:13: error: type mismatch;
found : (String, Wrapper[String]) => String
required: Int
"" { (a: String, x: Wrapper[String]) => a + x }
^
scala> "" apply { (a: String, x: Wrapper[String]) => a + x }
<console>:13: error: type mismatch;
found : (String, Wrapper[String]) => String
required: Int
"" apply { (a: String, x: Wrapper[String]) => a + x }
^
Thus, your code is interpreted as
scala> xs foldLeft ("").apply{ (a: String, x: Wrapper[String]) => a + x }
<console>:14: error: type mismatch;
found : (String, Wrapper[String]) => String
required: Int
xs foldLeft ("").apply{ (a: String, x: Wrapper[String]) => a + x }
^
But why does it apply the functions applications rule? It would also be possible to apply the function literal as postfix operator. To find out why we get the shown error message wen need to look at SLS Scala Syntax Summary. There we can see the following:
InfixExpr ::= PrefixExpr
| InfixExpr id [nl] InfixExpr
PrefixExpr ::= [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr
SimpleExpr ::= ‘new’ (ClassTemplate | TemplateBody)
| BlockExpr
| SimpleExpr1 [‘_’]
SimpleExpr1 ::= Literal
| Path
| ‘_’
| ‘(’ [Exprs] ‘)’
| SimpleExpr ‘.’ id
| SimpleExpr TypeArgs
| SimpleExpr1 ArgumentExprs
| XmlExpr
Exprs ::= Expr {‘,’ Expr}
ArgumentExprs ::= ‘(’ [Exprs] ‘)’
| ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ‘)’
| [nl] BlockExpr
From the sections described above we know that ArgumentExprs describes function application while InfixExpr describes an infix expression. Because of the rules of EBNF, the most upper rule has the lowest precedence. And because the former rule is called by the latter one, it means that the function literal is applied before the infix expression, hence the error message.
I believe you can only use binary operators as infix notation. I think you can also remedy the situation by using parenthesis: (xs foldLeft ("")) { (a: String, x: Wrapper[String]) => a + x }.
Probably, it parses your original code as xs.foldLeft("").{ (a: String, x: Wrapper[String]) => a + x }. Check out this answer: When to use parenthesis in Scala infix notation
I have a simple unapply that checks of an integer is less than 10
object MatchLess {
def unapply(i: Int): Option[Int] = if ( i < 10 ) Some(i) else None
}
// so this prints
// 7 8 9 . . .
for ( i <- 7 to 12 ) i match {
case MatchLess(x) => print(x + " ") // line 8
case _ => print(". ")
}
I have one doubt about unapply syntax: why in case in line 8, value x is actually visible at both sides of =>? Can I assume that the compiler implicitly adds an assignment like this?
// ...
case /* val x = i */ MatchLess(x) => print(x + " ") // line 8
When you write case MatchLess(x) => ... the meaning is the following:
execute the unapply method
if it succeed, bind the variables (here x) to the values returned by unapply here the i of Some(i) (ohterwise, the pattern doesn't match, goes to the following.
So in your particular case the x is bound to the same value than i. But if instead of Some(i)the function MatchLess.unapplyreturns something else (for example Some(42)) x would have been bound to 42.
Check out the language spec, section 8 on pattern matching:
Syntax:
Pattern ::= Pattern1 { ‘|’ Pattern1 }
Pattern1 ::= varid ‘:’ TypePat
| ‘_’ ‘:’ TypePat
| Pattern2
Pattern2 ::= varid [‘#’ Pattern3]
| Pattern3
Pattern3 ::= SimplePattern
| SimplePattern {id [nl] SimplePattern}
SimplePattern ::= ‘_’
| varid // <- 2)
| Literal
| StableId
| StableId ‘(’ [Patterns] ‘)’ // <- 1)
| StableId ‘(’ [Patterns ‘,’] [varid ‘#’] ‘_’ ‘*’ ‘)’
| ‘(’ [Patterns] ‘)’
| XmlPattern
Patterns ::= Pattern {‘,’ Patterns}
MatchLess(x) is identified as a SimplePattern (1), and the expression between parentheses, according to the above, is identified via Patterns -> Pattern -> Pattern1 -> Pattern2 -> Pattern3 -> SimplePattern -> varid (2). This variable pattern is described as:
A variable pattern x is a simple identifier which starts with a lower
case letter. It matches any value, and binds the variable name to that
value. The type of x is the expected type of the pattern as given from
outside.
In your example, unapply is called on i, and the result is bound to x.