Do I need a trailing semicolon to disambiguate thi

2019-02-25 13:19发布

问题:

If I omit the semicolon, this code doesn't compile.

def checkRadioButton(xml: DslBuilder): String => XmlTree = {
    val inputs = top(xml).\\*(hasLocalNameX("input"));
    { (buttonValue: String) =>
      // code omitted
    }
}

My guess is that, without the semicolon, scalac thinks that the partial function is another argument to the \\* method, instead of the return value. (It isn't actually a partial function, by the way, it's a total function.)

Can I do without the semicolon here? I've never had to use a semicolon at the end of a line before in Scala.

回答1:

I’d write it like this instead:

def checkRadioButton(xml: DslBuilder): String => XmlTree = {
    val inputs = top(xml).\\*(hasLocalNameX("input"));
    (buttonValue: String) => { // <-- changed position of {
      // code omitted
    }
}


回答2:

Just add a second newline, which apparently is equivalent to the semicolon.

Still, I'm not entirely happy with this, as it seems fragile.



回答3:

Here is a simplification, explanation, and beautification.

Simplified,

scala> def f: String => String = {
     | val i = 7
     | { (x: String) =>
     |   "y"
     | }
     | }
<console>:9: error: Int(7) does not take parameters
       { (x: String) =>
       ^
<console>:12: error: type mismatch;
 found   : Unit
 required: String => String
       }
       ^

This fails because the newline after the 7 is not taken as a semicolon, for the reason that it might be a function application; you might want a DSL where the brace is on the next line. Here is the little nl in the syntax of an arg with braces.

Newline handling is described in 1.2 of the spec; a few spots like this one, where a single nl is accepted, are mentioned at the end of the section.

(Two newlines doesn't work, which is why that also fixes your problem.)

Notice that a nl is not accepted in front of a paren, so the following works (though with only parens, you get only one expression for your function literal):

scala> def g: String => String = {
     | val i = 7
     | ( (x: String) =>
     |   "y"
     | )
     | }
g: String => String

In fact, the best edit for the problem code is not more braces but fewer:

scala> def f: String => String = {
     | val i = 7
     | x: String =>
     | "y"
     | }
f: String => String

The reason for this nice syntax is that your method body is already a block expression, and when the result expression of a block is a function literal, you can simplify.

The type of x is also redundant.

scala> def f: String => String = {
     | val i = 7
     | x =>
     | val a = "a"
     | val b = "b"
     | a + i + x + b
     | }
f: String => String

And not surprisingly:

scala> def f: (String, Int) => String = {
     | val i = 7
     | (x, j) =>
     | x + (i + j)
     | }
f: (String, Int) => String

scala> f("bob",70)
res0: String = bob77