I am in process of porting a large project from Scala 2.13 to Scala 3. Until the process is complete, I still need the project to compile with Scala 2.13, therefore I cannot remove all implicits in favour of extensions and similar Scala 3 features.
I am experiencing an obstacle now which I have no idea how to deal with: I have an at method provided as a Scala 2 extension (using implicit class), but there is also an at method provided by Quicklens library, which, being already ported to Scala 3, is a proper Scala 3 extension.
Now the trouble is the compiler does not see my at method, even if the extension is not applicable.
object AtGiven {
class F[T]
trait Functor[F[_]]
extension[F[_] : [G[_]] =>> Functor[G], A] (fa: F[A]) {
def at(idx: Int): A = ???
}
val f = new F[Unit]
implicit class FOps[T](f: F[T]) {
def at(i: Int) = i
}
def main(args: Array[String]): Unit = {
val fi = f.at(0)
}
}
When I replace the implicit class with following extension, the code works fine:
extension [T](fa: F[T])
def at(i: Int) = i
This is however not a solution at this moment, because such code does not compile with Scala 2.13.
Are there any rules regarding extension vs. implicit class resolution priorities?
It this a Scala 3 compiler bug, feature, or limitation? How can I work around it?
Related
I am struggling with a problem and I can't realise how to solve it. I hope more experienced Scala programmers can shed me a light!
I have the following macro:
object Model {
trait Model[T <: Product] {
def showAttrs(): Unit
}
def getModel[T <: Product]: Model[T] = macro getModelImpl
}
The purpose of the macro is to return a Model instance that shows the T's attributes (if T is a case class)!
I want to be able to do the following:
def f[T <: Product](implicit m: Model[T]): Unit = {
m.showAttrs()
}
case class Number(n: Int)
f[Number]()
The principle is the same as scala reflection when we do the following:
case class Number(n: Int)
def getInfo[T](implicit tag: TypeTag[T]): Unit = println(tag)
See?! We get an instance of Type :) (GREAT!).
How to do such thing? Does the scala reflection package provide some concrete implicit behind the scenes? If so, how can I accomplish the same result?
What should your MyTypeTag[T] accomplish?
If your trait is invariant on T and has not any type-dependent logic at all, simplest solution could be define method
implicit def arbMyTypeTag[T] = new MyTypeTag { ... }
More complex variant depends on other resolved implicits
implicit def optionMonoid[T: Semigroup] = new Monoid[Option[T]] { ... }
Even more complex variant depends on same type
implicit def tupleMonoid[A,B](implicit ma: Monoid[A], mb: Monoid[B]) = new Monoid[(A,B)]{...}
Compiler is able to resolve such recursive implicits.
The most hardcore approach is to use whole compile-time information on type and expression via implicit macro which is the closest to things like TypeTag resolution, which could lead to very complex bugs
For implicit conversion in Scala, I can use either implicit conversion function
implicit def intToX(i:Int):X = new X(i)
1.myMethod // -1
or implicit class
implicit class X(i: Int) {
def myMethod = - i
}
1.myMethod // -1
Is there any difference between the two? When should I prefer one over the other?
There is a related question about implicit conversion vs. type class but it only compares implicit functions and type classes. What I am interested is the difference from implicit classes.
Implicit class is a syntax sugar for implicit method and a class:
http://docs.scala-lang.org/sips/completed/implicit-classes.html:
For example, a definition of the form:
implicit class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
will be transformed by the compiler as follows:
class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
implicit final def RichInt(n: Int): RichInt = new RichInt(n)
Implicit classes were added in scala 2.10 because it is was very common to define new class with defining implicit method conversion to it.
But if you do not need to define a new class but defining implicit conversion to existing class you should better use an implicit method
It's been a while sice you asked a question and it seems that things have changed since. Actually, you should always choose implicit classes over implicit conversions now.
Implicit conversions have been marked as an advanced language feature by scala and the compiler discourages use of them (at least in Scala 2.12). And you need to add an extra flag (-language:implicitConversions) to the compile options to turn it off. See scala-lang docs
Also, Scala community (or at least LightBend/Typesafe people) are even planning of getting rid of imlicit conversions in general. This was mention in a conference talk in 2017 Nov presenting Scala 2.13, you can find it here.
Here's two piece of example code, found here:
scala> val im = m.reflect(new C)
im: reflect.runtime.universe.InstanceMirror = instance mirror for C#3442299e
and here:
scala> def mkArray[T : ClassTag](elems: T*) = Array[T](elems: _*)
the first piece of code uses a method defined in scala.reflect.api.Mirrors (found here):
abstract def reflect[T](obj: T)(implicit arg0: ClassTag[T]): Universe.InstanceMirror
if you notice, there's a ClassTag used like ClassTag[T] and one used like ClassTag. What's the reason for the difference?
For the most part, both are equivalent.
foo[T: ClassTag]()
is syntactic sugar for
foo[T]()(implicit ct: ClassTag[T]
However, the difference between these signatures is that in the former, you have to access the ClassTag via implicitly[ClassTag[T]] while in the latter, you can just use ct
Syntax change note:
Before 2.10.x it used to not be possible to have have both a context bound like ClassTag and an implicit argument list, such as:
foo[T: ClassTag]()(implicit ex: ExecutionContext)
The error used to be reported as "Error: cannot have both implicit parameters and context bounds". IntelliJ 13 was still reporting it as late as 2.10.4, but is now accepted by the scala compiler.
In Scala 2.9 one could implement polymorphic instantiation as
def newInstance[T](implicit m: Manifest[T]) =
m.erasure.newInstance.asInstanceOf[T]
but as of 2.10 Manifest is being replaced with TypeTag,
and it is not clear to me how to achieve something similar with TypeTag.
I would prefer if the TypeTag version preserved all available type information.
I know that the above only works for traits/classes that do not require constructor args,
and ven then it does not always work, but it works well enough for what I need.
If I can do better the new reflection APIs that would be great.
TypeTag is not yet a replacement for Manifest because it's a part of experimental and unstable Scala reflection. You definitely shouldn't use it for production as of now.
For the use case you showed, where only runtime class is needed (not full type information with generics etc.), Scala 2.10 introduced ClassTag, which you can use like this:
def newInstance[T: ClassTag] =
implicitly[ClassTag[T]].runtimeClass.newInstance.asInstanceOf[T]
or:
def newInstance[T](implicit ct: ClassTag[T]) =
ct.runtimeClass.newInstance.asInstanceOf[T]
Anyway, Manifest isn't deprecated yet, so I guess you can still use it.
EDIT:
Using TypeTag to achieve the same:
import scala.reflect.runtime.universe._
def newInstance[T: TypeTag] = {
val clazz = typeTag[T].mirror.runtimeClass(typeOf[T])
clazz.newInstance.asInstanceOf[T]
}
The above solution still uses some Java reflection. If we want to be puristic and use only Scala reflection, this is the solution:
def newInstance[T: TypeTag]: T = {
val tpe = typeOf[T]
def fail = throw new IllegalArgumentException(s"Cannot instantiate $tpe")
val noArgConstructor = tpe.member(nme.CONSTRUCTOR) match {
case symbol: TermSymbol =>
symbol.alternatives.collectFirst {
case constr: MethodSymbol if constr.paramss == Nil || constr.paramss == List(Nil) => constr
} getOrElse fail
case NoSymbol => fail
}
val classMirror = typeTag[T].mirror.reflectClass(tpe.typeSymbol.asClass)
classMirror.reflectConstructor(noArgConstructor).apply().asInstanceOf[T]
}
If you want to support passing args, here's a trick I do with 2.11:
def newInstance[T : ClassTag](init_args: AnyRef*): T = {
classTag[T].runtimeClass.getConstructors.head.newInstance(init_args: _*).asInstanceOf[T]
}
Example usage:
scala> case class A(x:Double, y:Int)
defined class A
scala> newInstance[A](4.5.asInstanceOf[Object],3.asInstanceOf[Object])
res1: A = A(4.5,3)
When looking for implicits, the Scala compiler looks, among other places, in the companion object of the various parts of the classes involved. Apparently, though, it fails to perform this lookup when the implicit conversion is used in the class itself, if it is defined before the companion object. The minimal example I was able to cook up is:
trait Counter[A] {
def count(a: A): Int
}
object Foo {
def foo[A](a: A)(implicit c: Counter[A]) = c.count(a)
}
case class Bar(id: Int) {
import Foo._
def count = foo(this)
}
object Bar {
implicit object BarCounter extends Counter[Bar] {
def count(b: Bar) = b.id
}
}
This fails to compile saying could not find implicit value for parameter c: Counter[Bar] - I am using Scala 2.9.1.
The interesting thing (suggested by rjsvaljean) is that if we invert the order - that is, we define object Bar before case class Bar - verything compiles fine.
Is this a compiler bug? Or I am missing something about the scope rules of Scala?
I should also mention that this problem only arises with implicit resolution. If we explicitly pass the BarCounter object, everything compiles fine.
It seems to be an actual compiler bug. I have posted it here.