I’m writing a compiler out of micro-passes. Most build a tree from an input tree, but a very few modify their input tree in place. E.g.
fun f(inp: T): T {
var tree = inp
tree = passThatReturnsCopyWithAlterations(inp)
passThatModifiesInPlace(tree)
return tree
}
For the former, something like @CheckResult would be nice.
For the latter, I’d like a way to make it clear to readers that there’s no result to check or assign.
Is there an idiomatic way to do that?
I thought of using an infix operator thus
fun f(inp: T): T {
var tree = inp
// The assignment is explicit
tree = passThatReturnsCopyWithAlterations(inp)
// `calledFor` makes it clear that the lack of an assignment here is intentional.
passThatModifiesInPlace(tree) calledFor effect
return tree
}
This is trivially implementable thus:
infix fun Unit.calledFor(@Suppress("UNUSED_PARAMETER") e: EffectSentinel) =
this
/** A sentinel value accessible via the global name `effect`. */
class EffectSentinel private constructor () {
companion object {
internal val singleton = EffectSentinel()
}
}
val effect = EffectSentinel.singleton
Since there is no override for infix fun calledFor
for non-Unit this
, any attempt to apply calledFor effect
to a useful result would be caught at compile time.