Hi, I have a new proposition for improving for-comprehensions in Scala 3.
Motivation
I want to fix the problem that arises from the use of the following code:
//> using scala 3.3.3
//> using lib "dev.zio::zio:2.1.5"
import zio.*
def loop: Task[Unit] =
for
_ <- Console.print("loop")
_ <- loop
yield ()
@main
def run =
val runtime = Runtime.default
Unsafe.unsafe { implicit unsafe =>
runtime.unsafe.run(loop).getOrThrowFiberFailure()
}
This kind of effect loop is pretty commonly used in Scala FP programs and often ends in yield ().
The problem with the desugaring of this for-comprehensions is that it leaks memory because the result of loop has to be mapped over with _ => (), which often does nothing.
Proposed Solution
A possible solution that I want to suggest and possibly add to the betterFors language extension is to remove these unnecessary map calls generated from yield () when the last binding also has type Unit.
A possible approach could be to add sticky keys to the map calls generated from for-comprehensions and add a new phase after. That phase would then check for every such map call if the argument is equivalent to _ => () and the previous binding is also of type Unit.
A naive PoC: Crude implementation of removing trailing unit-literal maps from for-… · KacperFKorban/dotty@31cbd47 · GitHub
Discussion
These changes can be introduced as either a separate SIP or as an addition to the SIP-62 (betterFors).
Let me know what you think.