I have a proposal that we desugar if statements in the same manner as the desugaring of for does. This allows if to be customizable in the same way as for, which I think makes Scala more consistent.
Essentially
if (condition) t else f
is desugared into
condition.cond(t, f)
with cond having the following signature:
def cond[A](t: => A, f: => A): R
This might be useful in a few cases. E.g.:
Given a probability monad Stochastic[+_], and if we have a probabilistic Boolean, we could do
val coinFlip: Stochastic[Boolean]
val t: A
val f: A
val r: Stochastic[A] = if (coinFlip) t else f
This is more declarative for probabilistic programming than using a monadic comprehension:
val r = for (isObverse <- coinFlip) yield if (isObverse) t else f
Or in an autodiff system (i.e. deep learning) when we build a computation graph conditioned on the value of a variable:
val c: Symbolic[Boolean]
val t: Symbolic[A]
val f: Symbolic[A]
val r = Conditional(c, t, f)
// creates a conditional expression whose result depends on c at runtime
// compare `tf.cond` in TensorFlow and `torch.where` in PyTorch
We could make this into a more readable form:
val r = if (c) t else f
I agree that this is rather niche, but in my opinion would be a nice addition.
It’s for a DSL, so we can get information on both branches of the if. Do I need to create a special myIf to handle a MyBoolean condition and return => MyRetType for then/else branches.
It would be very useful for DSLs. It’s a shame, little of scala-virtualized has ever made it into the main language.
If the desugaring is handled dynamically, like looking up default values, perhaps the cond signature could also ask for implicit parameters (e.g. context) when needed by a particular DSL.
It’s a matter of compiler optimisation. You could still have a virtualised while that does not need to create a lambda when the receiver is Boolean. Wasn’t there a plan to optimise for for some cases (such as using a Range)? What happened to that?
If it is an actual Boolean in the if condition, I’m sure that the compiler can rewrite it to a simple JVM if. I guess that the same can be done for for (i <- x to y) (as for why it is not rewritten, I don’t know).
I think that the compiler does not have to decide whether it is " actual Boolean" or " dsl Boolean".
it’s too complicated.
Of course the compiler should make optimization. But it is a complex task in general, for example Virtualized-Scala-Reference. So I prefer to have guarantee that neither compiler nor I make mistake.
I don’t think it’s an issue. The compiler already rewrites a method call a.&&(b) to specialized bytecode when a is a Boolean. It could easily do the same for a.cond(b, c).