To be able to use var we need to extend Expr[T] with a VarExpr[T] that allows the expression to be used in the left-hand side of an expression.
def whileNotZero(body: VarExpr[Int] => Expr[Unit]) = '{
var x = 0
while (x == 0) ~body('(x))
}
whileNotZero(x => '{ ~x = ~x - 1 })
Currently in '{ ~x = ~x - 1 }, the left hand side cannot be spliced in. The VarExpr[T] would allow x to be spliced on the left hand side of the assignment.
@nicolasstucki Maybe with some guidance I could have a look into that.
We should first merge #3883 or build on top of it. I am currently not sure how it should work exactly. I would have to experiment with it to be able to give some guidance.
An alternavie library implementation is possible
sealed abstract class VarRef[T] {
def update(expr: Expr[T]): Expr[Unit]
def expr: Expr[T]
}
object VarRef {
def apply[T: Type, U](init: Expr[T])(body: VarRef[T] => Expr[U]): Expr[U] = '{
var x = ~init
~body(
new VarRef {
def update(e: Expr[T]): Expr[Unit] = '{ x = ~e }
def expr: Expr[T] = '(x)
}
)
}
}
object Test {
VarRef(4)(varRef => '{ ~varRef.update(3); ~varRef.expr })
}
But there is a bug when splicing ~e, it emits an error with value 'apply' is not a member of scala.quoted.Expr[Unit] (see #4044).
Fix will be possible after changes in #4081
Fixed by #4081
Most helpful comment
An alternavie library implementation is possible
But there is a bug when splicing
~e, it emits an error withvalue 'apply' is not a member of scala.quoted.Expr[Unit](see #4044).