Suppose that I have some typeclass
trait FooBar[X]
and an instance of FooBar[Int]:
given intIsFooBar: FooBar[Int] = new FooBar {}
Now, suppose that I have an interface Intf that has some member type A and also guarantees that there is a given FooBar[A]:
trait Intf:
type A
given aIsFoobar: FooBar[A]
Now, I have the type Int, and I have a FooBar[Int], but how do I actually implement this interface for Int?
If I try
class IntImpl() extends Intf:
type A = Int
given aIsFoobar: FooBar[A] = summon
then I get "Infinite loop in function body IntImpl.aIsFoobar" errors, because the summon seems to see the aIsFoobar instead of intIsFooBar.
If I try to summon the instance in some auxiliary helper variable, like so:
class IntImpl() extends Intf:
type A = Int
private final val _aIsFoobar: FooBar[A] = summon
given aIsFoobar: FooBar[A] = _aIsFoobar
then I run into initialization order issues: aIsFoobar turns out to be null, and my application crashes with NullPointerExceptions, which is kinda ridiculous.
I've also tried export, but none of this works:
export FooBar[Int] as aIsFoobar // doesn't compile, invalid syntax
How do I make "the canonical" FooBar[Int] available as the aIsFoobar given member?
Full code:
trait FooBar[X]
given intIsFooBar: FooBar[Int] = new FooBar {}
trait Intf:
type A
given aIsFoobar: FooBar[A]
object IntImpl extends Intf:
type A = Int
given aIsFoobar: FooBar[A] = summon
In Scala 2 you can use the trick with hiding implicit by name
NullPointerException on implicit resolution
In Scala 3, what's the canonical method for pattern match that uses an erased type?
Is there a workaround for this format parameter in Scala?
Extending an object with a trait which needs implicit member
Constructing an overridable implicit (answer)
In Scala 3 this trick doesn't work any more.
In Scala 3 you can try to make the method inline and use
scala.compiletime.summonInlinerather than the ordinarysummonOverriding inline methods: https://docs.scala-lang.org/scala3/reference/metaprogramming/inline.html#rules-for-overriding
Please notice that with inlining we modified the method semantics. The implicit is resolved at the call site, not at the definition site
About the difference
implicitlyvs.implicit:When doing implicit resolution with type parameters, why does val placement matter?
Why the Scala compiler can provide implicit outside of object, but cannot inside? (answer)
Setting abstract type based on typeclass
SYB `cast` function in Scala
In scala 2, can macro or any language feature be used to rewrite the abstract type reification mechanism in all subclasses? How about scala 3?
In Scala 2.13, why is it possible to summon unqualified TypeTag for abstract type?
In Scala 2 inlining can be achieved with Scala 2 macros.
Implicit Json Formatter for value classes in Scala
In https://docs.scala-lang.org/scala3/reference/contextual/relationship-implicits.html#abstract-implicits it's written
You can ask how to override implicit in Scala 3 not changing the definition-site semantics. Probably, just resolving the implicit manually rather than using
summonMore general but less conventional solution would be with Scala 3 macros + compiler internals
Finding the second matching implicit
Or you can try to make
Aa type parameter rather than type memberhttps://docs.scala-lang.org/scala3/reference/changed-features/implicit-resolution.html
@AndreyTyukin's solution: