Skip to content

Fix the syntax of if and while #9746

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
smarter opened this issue Sep 7, 2020 · 10 comments
Closed

Fix the syntax of if and while #9746

smarter opened this issue Sep 7, 2020 · 10 comments

Comments

@smarter
Copy link
Member

smarter commented Sep 7, 2020

This compiles but shouldn't (we should require then when using indentation syntax)

if cond
  fooA()
  fooB()

This compiles in Scala 2.13 but not in Dotty, but we should be able to support it:

var i = 0
while
  (i < 10) { i += 1 }

/cc @kpbochenek

@kpbochenek
Copy link
Contributor

kpbochenek commented Sep 8, 2020

So just to be on the same page, let's formalize that:

cond can be of 3 forms(that will be used later):

  • cond <- where there is NO '(' at the beginning
  • (cond) <- where a whole condition is wrapped in ()
  • (cond).cont <- where it starts with '(' but has continuation either via '.method(...)' or via infix operator

A few examples from dotty repl:

Statement with (cond) currently works

scala> if (2 < 3)
     |   println("a")
     |   println("b")
     |
a
b

Statement with cond currently works

scala> if 2 < 3
     |   println("a")
     |   println("b")
     |
a
b

Statement with (cond).cont currently works

scala> if (1 + 2) < 5
     |   println("a")
     |   println("b")
     |
a
b

@smarter what 'cond' do you mean in if example, all 3? just a question, trying to clarify as much as possible to have common understanding and move to more interesting things :)

@smarter
Copy link
Member Author

smarter commented Sep 8, 2020

None of these examples should work.

@kpbochenek
Copy link
Contributor

That was quick 👍

docs might need to be updated: https://dotty.epfl.ch/docs/reference/other-new-features/control-syntax.html
The condition of an if-expression can be written without enclosing parentheses if it is followed by a then or some indented code on a following line (it must be followed by 'then')

@som-snytt
Copy link
Contributor

I too read the docs recently and liked thenless indented block syntax.

In fact, I would also like doless indented block syntax for while.

if x < 10
  println(x)
  x += 1
while x < 10
  println(x)
  x += 1

Full disclosure, last week I wrote one multiline if and used then. Yesterday I wrote only one-liners using then. I wrote no while, only recursive methods.

I agree that it's the other syntax that is problematic, which we should call "legacy parens".

In fact, I'm not sure what work the parser is doing, but the only problem seems to be that it doesn't like an indented condition, which IMHO ought to be (easily) supported:

if
(x < 10) && true
  x += 1  // ok
if
  (x < 10) && true
  x += 1  // you confused me with an indented block, but you didn't even see a condition yet

It seems to me that accepting the indented condition solves all these problems.

if
  (x < 10 && true) x += 1  // legacy parens, OK only if not indented (same as reported legacy parens in while syntax)

In sum, it shouldn't matter if the condition begins on the next line, and while should accept optional do the same way if accepts optional then, when followed by an indent block.

@LPTK
Copy link
Contributor

LPTK commented Sep 9, 2020

I really dislike then-less & paren-less if. Dotty is supposed to simplify the language, so it's already a stretch to introduce a new way of writing conditionals. But then, this would introduce a third, totally unnecessary way?

This issue has demonstrated that then-less if is confusing enough, so why not just use then consistently instead? This reads much better to me:

if x < 10 then
  println(x)
  x += 1

if
(x < 10) && true then
  x += 1

if
  val tmp = ...
  tmp > 0
then
  ...

@som-snytt
Copy link
Contributor

I did not consider the third example, a braceless indented block for the condition.

The compelling example is the block condition for while in https://dotty.epfl.ch/docs/reference/dropped-features/do-while.html

It says do-while was rare, and therefore block condition for this usage is rare, so it's not terrible to require braces.

The argument for discouraging block condition is that it's harder to read.

Is it terrible to require then and do always when most conditions are one-liners?

I don't have very strong opinions about this syntax because I'm suspending judgment while I gain more experience.

It's possible "optional then" and "support legacy parens with arbitrary indents" are orthogonal issues.

@kpbochenek
Copy link
Contributor

kpbochenek commented Sep 14, 2020

Potentially worth taking into account as it is about if syntax: #9790

@odersky
Copy link
Contributor

odersky commented Sep 23, 2020

There are three choices here to make for the interplay with indentation and ifs:

  1. allow indentation only after a then. Plus: this is simplest and pushes towards one coding style only. Minus: It leaves out one common case where we can infer braces, so brace inference will look more random and arbitrary to people.

  2. allow indentation after a then and after an old style if (...). Plus: More orthogonality between if syntax ad brace insertions.

  3. Allow indentation to replace then. Plus: least hassle for transitions; some people like the style. Minus: Might be too many different styles.

My tendency would be to go with (2).

anatoliykmetyuk added a commit that referenced this issue Sep 24, 2020
Fix #9746: Require `then` in new conditional syntax
@tgodzik
Copy link
Contributor

tgodzik commented Oct 16, 2020

@odersky @anatoliykmetyuk Just to be sure, are we keeping it at (2) or at (1)? I see there is still things like https://github.com/lampepfl/dotty/blob/5274c48767c655bcf9d994f649b43f0e7214dde9/compiler/src/dotty/tools/dotc/typer/Checking.scala#L479-L481 so I am guessing it's (2) ?

@tgodzik
Copy link
Contributor

tgodzik commented Oct 16, 2020

And isn't this going against what Dotty is trying to do? By which I mean we want reduce the number of ways to do the same thing. We removed the optional = and now we are actually adding optional then

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants