Skip to content

Clarification of intended ’if … then’ new control syntax interaction with newlines #12757

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
djneades opened this issue Jun 8, 2021 · 4 comments · Fixed by #12801
Closed
Assignees
Milestone

Comments

@djneades
Copy link

djneades commented Jun 8, 2021

Compiler version

3.0.0

Minimized code

This compiles:

val x = Some(10)

def f =
   if x.exists(x => x == 10) then
      println("Yes")
   else
      println("No")

But this does not:

val x = Some(10)

def f =
   if x.exists
        (x => x == 10) then
      println("Yes")
   else
      println("No")

Expectation

Given that Scala 3 allows method calls like this in other contexts:

foo
  (arg)

the if x.exists … in the second example above seems at least intuitively plausible, even though it doesn’t compile. Clarification as to whether or not that latter example should be considered valid would be appreciated. (The New Control Syntax page doesn’t obviously settle the matter.)

My doubt here arises from:

  1. whether the newline after the if x.exists should terminate the if condition, as it currently seems to do in Scala 3.0.0;

  2. or whether the if condition should instead be considered to continue up until the following then, the newline before the indented argument to x.exists being treated as it would be in other contexts.

Interestingly, this does compile:

val x = Some(10)

def f =
   if
      x.exists
         (x => x == 10) then
      println("Yes")
   else
      println("No")

As does:

val x = Some(10)

def f =
   if
      x.exists
         (x => x == 10)
   then
      println("Yes")
   else
      println("No")

Note that this question arose in this Scalafmt-related comment.

@djneades djneades changed the title Clarification of intended new if … then control syntax interaction with newlines Clarification of intended if … then new control syntax interaction with newlines Jun 8, 2021
@djneades djneades changed the title Clarification of intended if … then new control syntax interaction with newlines Clarification of intended ’if … then’ new control syntax interaction with newlines Jun 8, 2021
@djneades
Copy link
Author

djneades commented Jun 8, 2021

(Description edited.)

@som-snytt
Copy link
Contributor

som-snytt commented Jun 9, 2021

This is analogous to for ( ... ) vs for { ... }, where analogous means just the same.

"Braced" or "block" behavior, but with the braces optional, needs an indent:

def f =
   if
      x.exists
        (_ == 10)
   then
      "Yes"
   else
      "No"

Otherwise, the if conditional will keep hoovering up an ordinary expression that continues on the next line, whether or not it started with a paren:

def p =
   if 1
      +
      2
      <
      4 then
      42
   else
      17

def q =
   if (1 + 2)
      <
      4 then
      42
   else
      17

The potential for ambiguity:

   if (1 + 2 < 4)
      (true)         // normal "is it a continued line" rules apply
   then

There is an intuition that it should take up to the then, as it does for case:

def k =
   x match
      case Some(y) =>
         x.exists
            (_ == y)
      case _ =>
         false

Usual example where we need to add grouping parens:

def g = (
   x.exists
        (_ == 10)
)

I don't remember if they plan to keep traditional paren syntax; if quiet syntax becomes standard, then they can vacuum to the next then, which would be required.

Footnote: I tried out 3-space indents here! but frankly, with top-level defs, I don't really indent much any more.

@tgodzik
Copy link
Contributor

tgodzik commented Jun 9, 2021

This one is pretty weird:

def f =
   if
      x.exists
         (x => x == 10) then
      println("Yes")
   else
      println("No")

and if can start and indented block, which seems to be the case in this place, but then should be an error here.

@som-snytt
Copy link
Contributor

There is the (provisional) rule for "parsing of legacy code with ad-hoc layout." https://dotty.epfl.ch/docs/reference/other-new-features/indentation.html

odersky added a commit to dotty-staging/dotty that referenced this issue Jun 12, 2021
In a statement like this
```scala
if foo
    (bar)
then
```
we would never expect a semicolon to be inserted between `foo` and `bar`. The `foo`
would need to be indented itself for this to happen.

So, the following is OK
```scala
if
  val x = ...
  x > 0
then
```
But the following is not:
```scala
if val x = ...
  x > 0
```

Fixes scala#12757
@Kordyjan Kordyjan added this to the 3.0.2 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants