Hi!
I have a question about if
expressions that have no else
clause. It’s generally inappropriate to access the value of such an expression, but beginners make mistakes and the symptoms (incl. consequent error messages) matter.
Here’s some toy code in Scala 2:
val x = 123
val foo = if (x > 0) 1 // type of foo is AnyVal
val bar = if (x > 0) 1 else if (x < 0) 2 // type of bar is AnyVal
And the same in Scala 3:
val x = 123
val foo = if x > 0 then 1 // type of foo is Unit(!)
val bar = if x > 0 then 1 else if x < 0 then 2 // type of bar is AnyVal
I love Scala 3, but the way Scala 2 treats these expressions seems simpler to explain. Moreover, such code is generally written in error, and Scala 2 produces more consistent symptoms.
I wonder if the change in Scala 3 is intentional and permanent?
The actual behavior is the same in both.
What happens is that conceptually an else ()
is added.
However, in Scala 3 they also apply the value discard rule, so the then
branch becomes { ..; () }
This makes total sense, an if
without else
is just for performing side-effects; thus, should not be assigned to a value.
2 Likes
Assigning a Unit-typed if-expression to a val or val is probably a bug. Perhaps this should be a case where the compiler emits a warning. Or it could be a rule in Scalafix or Scala Wartremover (I quickly searched for missing else but could not find any such rule).
3 Likes
Assigning a Unit-typed if-expression to a val or val is probably a bug. Perhaps this should be a case where the compiler emits a warning.
It’s definitely a bug in a well-ordered world.
For dealing with The Good, The Bad, and The Ugly in my work-day code ( … try blocks, nulls…) - an if statement that’s kicking off some side effect has to return a “there’s nothing to see here” value to stay part of The Good to fit in contexts of IO or Either. I deal with having to distinguish between Unit and AnyVal by declaring it to be Unit.
Do you think the presence of “there’s nothing to see here” values like Unit, or AnyVal, (or Any, or Nothing, or Object) indicates the bug better than “if with no else”? Unit seems to be OK at the tail-end of side effects; in my code the rest of them are signs of trouble.
I agree that a good warning message would be nice.
Actually, we already get a warning for such if
expressions because of the discarded value. Unfortunately, the warning points at the then
branch and says A pure expression does nothing in statement position; you may be omitting necessary parentheses, which can be unhelpful or even misleading in practice.
Incidentally, the issue isn’t constrained to val
s and var
s. Here’s a def
:
def foo(x: Int) =
if x != 0 then
100 / x
if x == 0 then
0
Code like that is problematic in more than one way, but it’s nevertheless code that neophytes do write. A good warning message would help.
2 Likes