Cats auto derived with Seq - scala

I want to define equality for some type that can be part of other objects or collections using cats/kitten. I don't want to have to define the equality for every other class.
For example:
import cats.Eq
case class Foo(a: Int, bar: Bar)
case class Bar(b: Int)
object BarEq {
implicit val barEq: Eq[Bar] = Eq.instance[Bar] {
(b1, b2) => b1.b +1 == b2.b
}
}
and then a test defined as
import cats.derived.auto.eq._
class BarEqTest extends FlatSpec with cats.tests.StrictCatsEquality {
import BarEq._
"bareq" should {
"work" in {
Foo(1, Bar(1)) should ===(Foo(1, Bar(2)))
Bar(1) should ===(Bar(2))
Some(Foo(1, Bar(1))) should ===(Some(Foo(1, Bar(2))))
}
}
}
this works fine, but if I try to add the following test case
Seq(Foo(1, Bar(1))) should ===(Seq(Foo(1, Bar(2))))
I get
[Error] types Seq[Foo] and Seq[Foo] do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[Seq[Foo],Seq[Foo]]
one error found
How come the auto derived eq works with Option but not Seq, and how can I make it work?
I tried to add import cats.instances.seq._ but that did not work either.

Cats defines an instance of Eq for scala.collection.immutable.Seq, not for generic scala.collection.Seq (or moreover scala.collection.mutable.Seq)
import scala.collection.immutable.{BitSet, Queue, Seq, SortedMap, SortedSet}
private[kernel] trait EqInstances0 {
implicit def catsKernelEqForSeq[A: Eq]: Eq[Seq[A]] = cats.kernel.instances.seq.catsKernelStdEqForSeq[A]
}
https://github.com/typelevel/cats/blob/main/kernel/src/main/scala/cats/kernel/Eq.scala#L283-L285
Starting from Scala 2.13.0 scala.Seq is scala.collection.immutable.Seq. But in Scala 2.12.x scala.Seq is scala.collection.Seq.
https://github.com/scala/scala/releases/tag/v2.13.0
So in Scala 2.12 import correct collection type
import scala.collection.immutable.Seq
Seq(Foo(1, Bar(1))) === Seq(Foo(1, Bar(2))) // true
or define your own instance of Eq for necessary collections
import cats.kernel.instances.StaticMethods
implicit def genericSeqEq[A: Eq]: Eq[collection.Seq[A]] = new Eq[collection.Seq[A]] {
override def eqv(xs: collection.Seq[A], ys: collection.Seq[A]): Boolean =
if (xs eq ys) true
else StaticMethods.iteratorEq(xs.iterator, ys.iterator)
}
Seq(Foo(1, Bar(1))) === Seq(Foo(1, Bar(2))) // true

Related

Scala macro: get companion object from class type

I cannot manage to get the companion object / singleton from a class type in Scala macro / quasiquotes. Tried to follow https://docs.scala-lang.org/overviews/quasiquotes/type-details.html#singleton-type, the given example works but it is based on a literal string to quasiquote to get the companion object directly, which I cannot quite achieve the same thing if I start off from an extracted class type of a param after some quasiquote unlifting.
I have simplified and tried to highlight the intended usage, and current macro implementation below:
// Intended usage
package utils
sealed trait Base
object Base {
import macros._
#Component
final case class X(v: XInner) extends Base
}
final case class XInner(v: Int)
Base.X(123) // No need to do Base.X(XInner(123))
The current macro implementation
package macros
import scala.reflect.macros.whitebox
import scala.language.experimental.macros
import scala.annotation.StaticAnnotation
import scala.annotation.compileTimeOnly
class Component() extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro ComponentMacro.impl
}
private class ComponentMacro(val c: whitebox.Context) {
import c.universe._
// To map function result while allowing the use of params forwarding syntax like `apply _`
// e.g. `def y = (X.apply _).mapResult(Y(_))`
implicit class Func1Extra[I1, O1, O2](f: I1 => O1) {
def mapResult(g: O1 => O2): I1 => O2 = (i1: I1) => g(f(i1))
}
def impl(annottees: Tree*): Tree = annottees match {
case (clsDef: ClassDef) :: Nil =>
clsDef match {
case q"final case class $className(..$fields) extends ..$parents" if fields.length == 1 => {
val fieldType = fields(0).tpt
val singletonType = tq"$fieldType.type"
val tq"$singleton.type" = singletonType
q"""
$clsDef
object ${clsDef.name.toTermName} {
def apply = (${singleton}.apply _).mapResult(new ${clsDef.name}(_))
}
"""
}
case _ => c.abort(c.enclosingPosition, "Invalid annotation target")
}
case _ => c.abort(c.enclosingPosition, "Invalid annotation target")
}
}
The error while compiling is:
value apply is not a member of Utils.XInner
The error message seems to suggest that the apply method was done on the XInner class type, rather than the companion object of XInner.
Any idea as to how to get the component object of the same type name? Thanks in advance!

why do implicits not trigger in this type dependent paths scenario

Let's say I define some type in a trait, that should implement some type class (like functor):
import cats.Functor
import cats.syntax.functor.toFunctorOps
trait Library {
type T[+A]
implicit val isFunctor: Functor[T]
}
Now, I want to use this library. The following works fine:
trait LibraryUser {
val l: Library
import l._
def use: T[Boolean] = {
val t: T[Int] = ???
t.map(_ => true)
}
}
But when using it in a method with a parameter instead, the import of the implicit isn't working (out commented line doesn't compile) and you have to write the implicit for yourself instead:
object LibraryUser1 {
def use(l: Library): l.T[Boolean] = {
import l._
val t: T[Int] = ???
//t.map(_ => true)
toFunctorOps(t)(isFunctor).map(_ => true)
}
}
Why is this the case / what can be done against it.
This has previously been filed as a bug, specifically SI-9625. Implicits values that are path-dependent and return higher-kinded types fail to resolve. Here is a simplified example using the standard library:
trait TC[F[_]]
trait Foo {
type T[A]
implicit val ta: TC[T]
}
object Bar {
def use(foo: Foo) = {
import foo._
implicitly[TC[T]] // fails to resolve, but `implicitly[TC[T]](ta)` is fine
}
}
Sadly, even the most obvious use of the implicit fails:
object Bar {
def use(foo: Foo) = {
implicit val ta: TC[foo.T] = null
implicitly[TC[foo.T]] // nope!
}
}

Scala macro - Infer implicit value using `c.prefix`

c.inferImplicitValue infers implicit values in the call site scope. Is it possible to infer implicits using the c.prefix scope?
This is not valid code, but expresses what I need:
c.prefix.inferImplicitValue
I'm currently using a naive implementation for this purpose[1], but it has some limitations like not inferring implicit values from defs and detecting duplicated/ambiguous implicit values.
[1] https://github.com/getquill/quill/blob/9a28d4e6c901d3fa07e7d5838e2f4c1f3c16732b/quill-core/src/main/scala/io/getquill/util/InferImplicitValueWithFallback.scala#L12
Simply generating a block with an appropriate (local) import followed by a call to implicitly does the trick:
q"""{import ${c.prefix}._; _root_.scala.Predef.implicitly[$T] }
Where T is an instance of Type representing the type of the implicit value to lookup.
To check if the implicit lookup actually succeeded, you can call Context.typeCheck with silent=true and check if the resulting tree is empty or not.
As an illustration, here is an example that implements an infer method returning None if the implicit was not found in the members of the target object, and otherwise wraps the result in a Some.
import scala.reflect.macros.Context
import scala.language.experimental.macros
def inferImplicitInPrefixContext[T:c.WeakTypeTag](c: Context): c.Tree = {
import c.universe._
val T = weakTypeOf[T]
c.typeCheck(
q"""{
import ${c.prefix}._
_root_.scala.Predef.implicitly[$T]
}""",
silent = true
)
}
def infer_impl[T:c.WeakTypeTag](c: Context): c.Expr[Option[T]] = {
import c.universe._
c.Expr[Option[T]](
inferImplicitInPrefixContext[T](c) match {
case EmptyTree => q"_root_.scala.None"
case tree => q"_root_.scala.Some($tree)"
}
)
}
trait InferOp {
def infer[T]: Option[T] = macro infer_impl[T]
}
Let's test it:
object Foo extends InferOp {
implicit val s = "hello"
}
Foo.infer[String] // res0: Some[String] = Some(hello)
Foo.infer[Int] // res1: None.type = None
implicit val lng: Long = 123L
Foo.infer[Long] // res2: Some[Long] = Some(123)

Scala: Multiple implicit conversions with same name

Using scala 2.10.3, my goal is to make the following work:
object A {
implicit class Imp(i: Int) {
def myPrint() {
println(i)
}
}
}
object B {
implicit class Imp(i: String) {
def myPrint() {
println(i)
}
}
}
import A._
import B._
object MyApp extends App {
3.myPrint()
}
This fails with
value myPrint is not a member of Int
If I give A.Imp and B.Imp different names (for example A.Imp1 and B.Imp2), it works.
Diving a bit deeper into it, there seems to be the same problem with implicit conversions.
This works:
object A {
implicit def Imp(i: Int) = new {
def myPrint() {
println(i)
}
}
implicit def Imp(i: String) = new {
def myPrint() {
println(i)
}
}
}
import A._
object MyApp extends App {
3.myPrint()
}
Whereas this doesn't:
object A {
implicit def Imp(i: Int) = new {
def myPrint() {
println(i)
}
}
}
object B {
implicit def Imp(i: String) = new {
def myPrint() {
println(i)
}
}
}
import A._
import B._
object MyApp extends App {
3.myPrint()
}
Why? Is this a bug in the scala compiler? I need this scenario, since my objects A and B derive from the same trait (with a type parameter) which then defines the implicit conversion for its type parameter. In this trait, I can only give one name for the implicit conversion. I want to be able to import more of these objects into my scope. Is there a way to do that?
edit: I can't give the implicit classes different names, since the examples above are only breaking down the problem. My actual code looks more like
trait P[T] {
implicit class Imp(i: T) {
def myPrint() {
...
}
}
}
object A extends P[Int]
object B extends P[String]
import A._
import B._
The implicits just have to be available as a simple name, so you can rename on import.
Just to verify:
scala> import A._ ; import B.{ Imp => BImp, _ }
import A._
import B.{Imp=>BImp, _}
scala> 3.myPrint
3
Actually, it works if you replace
import A._
import B._
with
import B._
import A._
What happens, I think, is that A.Imp is shadowed by B.Imp because it has the same name. Apparently shadowing applies on the function's name and do not take the signature into account.
So if you import A then B, then only B.Imp(i: String) will be available, and if you import B then A, then only A.Imp(i: Int) will be available.
If you need to use both A.Imp and B.Imp, you must rename one of them.
In case anyone else runs into this issue, there is a partial workaround, which I found here:
https://github.com/lihaoyi/scalatags/blob/3dea48c42c5581329e363d8c3f587c2c50d92f85/scalatags/shared/src/main/scala/scalatags/generic/Bundle.scala#L120
That code was written by Li Haoyi, so you can be pretty confident that no better solution exists...
Essentially, one can still use traits to define methods in terms of each other, but it will require boilerplate to copy those implicits into unique names. This example might be easier to follow:
trait Chainable
object Chainable {
implicit val _chainableFromInt = IntChainable.chainable _
implicit val _chainableFromIntTrav = IntChainable.traversable _
implicit val _chainableFromIntOpt = IntChainable.optional _
implicit val _chainableFromIntTry = IntChainable.tried _
implicit val _chainableFromDom = DomChainable.chainable _
implicit val _chainableFromDomTrav = DomChainable.traversable _
implicit val _chainableFromDomOpt = DomChainable.optional _
implicit val _chainableFromDomTry = DomChainable.tried _
private object IntChainable extends ImplChainables[Int] {
def chainable(n:Int) = Constant(n)
}
private object DomChainable extends ImplChainables[dom.Element]{
def chainable(e:Element) = Insertion(e)
}
private trait ImplChainables[T] {
def chainable(t:T):Chainable
def traversable(trav:TraversableOnce[T]):Chainable =
SeqChainable(trav.map(chainable).toList)
def optional(opt:Option[T]):Chainable =
opt match {
case Some(t) => chainable(t)
case None => NoneChainable
}
def tried(tried:Try[T]):Chainable =
optional(tried.toOption)
}
}
In other words, never write:
trait P[T] {
implicit def foo(i: T) = ...
}
object A extends P[X]
Because defining implicits in type parameterized traits will lead to these naming conflicts. Although, incidentally, the trait in mentioned in the link above is parameterized over many types, but idea there is that none of the implementations of that trait are ever needed in the same scope. (JSDom vs Text, and all._ vs short._ for those familiar with Scalatags)
I also recommend reading: http://www.lihaoyi.com/post/ImplicitDesignPatternsinScala.html
It does not address this issue specifically but is an excellent summary of how to use implicits.
However, putting all these pieces together, this still seems to be an issue:
trait ImplChainables[AnotherTypeClass]{
type F[A] = A=>AnotherTypeClass
implicit def transitiveImplicit[A:F](t: A):Chainable
implicit def traversable[A:F](trav: TraversableOnce[A]):Chainable = ...
}
What this trait would allow is:
object anotherImpl extends ImplChainables[AnotherTypeClass] {...}
import anotherImpl._
implicit val string2another: String=>AnotherTypeClass = ...
Seq("x"):Chainable
Because of the type parameter and the context binding (implicit parameter) those cannot be eta-expanded (i.e: Foo.bar _ ) into function values. The implicit parameter part has been fixed in Dotty: http://dotty.epfl.ch/blog/2016/12/05/implicit-function-types.html
I do not know if a complete solution would be possible, needless to say this is a complex problem. So it would be nice if same name implicits just worked and the whole issue could be avoided. And in any case, adding an unimport keyword would make so much more sense than turning off implicits by shadowing them.

Macros: knownDirectSubclasses broken with nested type?

I have a macro which enumerates the direct sub types of a sealed trait:
import scala.reflect.macros.Context
import language.experimental.macros
object Checker {
def apply[A]: Unit = macro applyImpl[A]
def applyImpl[A: c.WeakTypeTag](c: Context): c.Expr[Unit] = {
val tpe = c.weakTypeOf[A].typeSymbol.asClass
require (tpe.isSealed)
tpe.typeSignature // SI-7046
require (tpe.knownDirectSubclasses.nonEmpty)
import c.universe._
c.Expr[Unit](reify {} .tree)
}
}
Then this works:
sealed trait A
case class A1(i: Int) extends A
object NotNested {
val nada = Checker[A]
}
But this fails:
object Nested {
sealed trait A
case class A1(i: Int) extends A
val nada = Checker[A]
}
[error] java.lang.IllegalArgumentException: requirement failed:
Did not find sub classes
I thought I ran into SI-7046, so I added the call to tpe.typeSignature, but that doesn't help apparently.
I need a work around for this using Scala 2.10.2. Somehow I must enforce some extra type trees to be initialised, I guess?
A possible workaround is following (what do you think #EugeneBurmako).
val cls: ClassSymbol = sub.asClass
println(s"knownDirectSubclasses = ${cls.knownDirectSubclasses}")
// print "knownDirectSubclasses = Set()"
val subsub = cls.owner.typeSignature.decls.filter {
case c: ClassSymbol =>
cls != c && c.selfType.baseClasses.contains(cls)
case _ => false
}
println(s"subsub = $subsub")
// print the actual sub classes