Firstly (#3),
implicitly[ANumber[Int] => StoresNumeric[ANumber[Int], Int]]
is wrong. You do not define an implicit conversion from a data type to a type class, you define an implicit conversion from a data type to an implicit class introducing extension method. So it should be
implicitly[ANumber[Int] => StoresNumericSyntax.StoresNumericOps[ANumber[Int], Int]]
and it compiles.
Be prepared that implicitly[A => B]
not always checks that an implicit conversion from A
to B
exists. *
(see below)
Secondly (#4), when you use extension method (a.getNum
) you should import syntax object:
import StoresNumericSyntax._
(a: StoresNumericOps[ANumber[Int], Int]).getNum
compiles while
import StoresNumericSyntax._
a.getNum
produces (with scalacOptions += "-Xlog-implicits"
switched on)
Warning:
StoresNumericOps is not a valid implicit value for App.a.type => ?{def getNum: ?} because:
ambiguous implicit values:
both object BigIntIsIntegral in object Numeric of type scala.math.Numeric.BigIntIsIntegral.type
and object IntIsIntegral in object Numeric of type scala.math.Numeric.IntIsIntegral.type
match expected type Numeric[T]
If you import IntIsIntegral
you'll add this implicit to the local scope (before that it was in the implicit scope only), so you'll make its "priority" "higher" than the one of BigIntIsIntegral
. Try
import StoresNumericSyntax._
import Numeric.IntIsIntegral
a.getNum
It compiles.
Scala 2.13.3.
See also how to debug implicits (at compile time): In scala 2 or 3, is it possible to debug implicit resolution process in runtime?
*
For example if you modify the implicit class as @LuisMiguelMejíaSuárez advised in comments
object StoresNumericSyntax {
implicit class StoresNumericOps[A](private val value: A) extends AnyVal {
def getNum[T: Numeric](implicit sn: StoresNumeric[A, T]): T = sn.getNum(value)
}
}
then
import StoresNumericSyntax._
implicitly[ANumber[Int] => StoresNumericOps[ANumber[Int]]]
doesn't compile
Warning:
StoresNumericOps is not a valid implicit value for ANumber[Int] => StoresNumericSyntax.StoresNumericOps[ANumber[Int]] because:
hasMatchingSymbol reported error: type mismatch;
found : StoresNumericSyntax.StoresNumericOps.type
required: ANumber[Int] => StoresNumericSyntax.StoresNumericOps[App393.ANumber[Int]]
while manually resolved
implicitly[ANumber[Int] => StoresNumericOps[ANumber[Int]]](new StoresNumericOps(_))
compiles and
import StoresNumericSyntax._
a: StoresNumericOps[ANumber[Int]]
compiles too.
But if I remove extends AnyVal
object StoresNumericSyntax {
implicit class StoresNumericOps[A](private val value: A) /*extends AnyVal*/ {
def getNum[T: Numeric](implicit sn: StoresNumeric[A, T]): T = sn.getNum(value)
}
}
then
import StoresNumericSyntax._
implicitly[ANumber[Int] => StoresNumericOps[ANumber[Int]]]
compiles.
Also if I split the implicit class into a class + an implicit conversion
object StoresNumericSyntax {
/*implicit*/ class StoresNumericOps[A](private val value: A) extends AnyVal {
def getNum[T: Numeric](implicit sn: StoresNumeric[A, T]): T = sn.getNum(value)
}
implicit def toStoresNumericOps[A](value: A): StoresNumericOps[A] =
new StoresNumericOps(value)
}
then
import StoresNumericSyntax._
implicitly[ANumber[Int] => StoresNumericOps[ANumber[Int]]]
compiles.
Why implicitly[A => B]
is not the same as val x: B = ??? : A
is expained here:
In scala, are there any condition where implicit view won't be able to propagate to other implicit function?
When calling a scala function with compile-time macro, how to failover smoothly when it causes compilation errors?
Scala Kleisli throws an error in IntelliJ
What are the hidden rules regarding the type inference in resolution of implicit conversions?
Scala: `ambigious implicit values` but the right value is not event found
The impact of presence/absence of extends AnyVal
on implicit resolution can be a bug but difference between implicit instance (implicitly[A => B]
) and implicit conversion (val x: B = ??? : A
) is more or less intentional (different strategies of type inference, resolving type parameters are used).