I've been playing around with Scala 3's souped up inline
construct, which is a very cool, relatively approachable, bit of metaprogramming.
(See "Rock the JVM" for a quick explainer.)
A thing that confused me, though, is the ordering of inlining vs implicit resolution. Consider...
object InlineImplicitOrdering:
given Int = 10
inline def printIt(using i : Int) : Unit =
println(summon[Int])
object LocalContext:
given Int = 22
def printItLocally : Unit = printIt
@main
def go() =
printIt
LocalContext.printItLocally
It's straightforward that calling printIt
prints 10
.
It's not so straightforward what LocalContext.printItLocally
will do.
Implicit resolution is also a compile-time operation. If implicit resolution happens before the inlining, then LocalContext.printItLocally
might print 10
. If implicit resolution happens after the inlining is resolved, then LocalContext.printItLocally
should print 22
.
In reality, it prints 22
.
The output of this program is
10
22
I wondered whether this would always be the case, or whether adding modifiers might change this ordering. In particular I know that it's possible to declare inline given
, rather than straight given
, and I wondered whether this might cause the printIt
function to collapse to println(10)
.
The answer is no. As far as I can tell, there is no set of modifiers that would cause the implicit resolution to occur before the final inlining. Neither inline given
, nor transparent inline given
, nor marking the implicit argument inline
has this effect.
As far as I can tell, the hard and fast rule is that inline resolution is completed prior to any implicit resolution. Implicits will be resolved at the ultimate, inlined call site, and never before.
Which is the behavior I find that I want! I am glad it does not seem to be fragile.
(I'd still like to understand what inline given
is for, though.)