Skip to content

Unit-Insertion works differently in Scala 2 & Scala 3 #12890

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
Arthurm1 opened this issue Jun 21, 2021 · 5 comments
Closed

Unit-Insertion works differently in Scala 2 & Scala 3 #12890

Arthurm1 opened this issue Jun 21, 2021 · 5 comments

Comments

@Arthurm1
Copy link

Scala 3 handles unit-insertion differently to Scala 2

Compiler version

3.0.0 vs 2.13.6 - both using Scastie

Minimized code

val f: Boolean => Any = g => {
  if (g)
    1
}
println(f(true))
println(f(false))

Output - using Scala 3...

()
()

plus warning...
A pure expression does nothing in statement position; you may be omitting necessary parentheses

Expectation - as in Scala 2...

1
()

plus no warning

Comments

Scala 3 does give the above warning about a pure expression and changing the code to the following works...

val f: Boolean => Any = g => {
  if (g)
    1
  else
    ()
  }
}
println(f(true))
println(f(false))

From @smarter ...
"it looks like unit-insertion is working differently in scala 2 and 3 (in scala 2 it only inserts Unit in the missing branch, in Scala 3 it inserts it in both branches)"

@abgruszecki
Copy link
Contributor

IIRC, I think this was intentional - an if with only one branch is essentially treated as a side-effectful statement. @odersky can you comment?

@odersky
Copy link
Contributor

odersky commented Jun 29, 2021

Yes, that's intentional. I am not sure whether Scala 2's behavior was an accident, or whether there was some specific motivation behind it.

@odersky odersky closed this as completed Jun 29, 2021
@som-snytt
Copy link
Contributor

The behavior is specified:

A short form of the conditional expression eliminates the else-part. The conditional expression if (e1e_1e1​) e2e_2e2​ is evaluated as if it was if (e1e_1e1​) e2e_2e2​ else ().

Also the feature is not called "Unit insertion" (which sounds helpful) but "Value discard" (which sounds possibly dangerous).

@cayhorstmann
Copy link

Is the Scala3 behavior documented anywhere? In http://dotty.epfl.ch/docs/reference/syntax.html, Expr1 ::= ... [‘inline’] ‘if’ Expr ‘then’ Expr [[semi] ‘else’ Expr] ..., so an if without else is an expression, not a statement. It's not immediately intuitive that it should be an expression with value ()

@som-snytt
Copy link
Contributor

som-snytt commented Jul 21, 2021

I saw a tailrec method of the form def f: Unit = if (b) f and wondered does that even compile. It compiles for Unit result but not for Any. The Scala 2 rule, that if (b) expr means if (b) expr else (), is much easier to reason about, in that there is nothing to reason about.

import annotation._

class C() {
  //type R = Unit
  type R = Any
  @tailrec
  final def f(i: Int): R =
    if (i > 0) {
      println(s"$i ...")
      f(i-1)   // Cannot rewrite recursive call: it is not in tail position
    }
}

object Test extends App {
  val c = new C()
  println(c.f(5))
}

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