-1

Aloha! :)

I'm not happy about running all the time to the stackoverflow forums to get some help with another piece of strangeness scala/cats has thrown at me. Problem is: There seems to be no really useful documentation, only some worthless - at least for me - repl lines.

Could please somebody of you point to some useful documentation? Some real code? Not just lines in the repl?

Here I just tried to work with scala/cats Eq and Show typeclasses... What the hell am I doing wrong?

The class:

package org.hudelundpfusch.utilites.decisions.data

import cats.Show
import cats.kernel.Eq

case class Fact[+T <: Any](name: String, value: T)
  extends Equals {

  override def canEqual(that: Any): Boolean = that match {
    case _: Fact[_] => true
    case _          => false
  }

  override def equals(other: Any): Boolean = other match {
    case that: Fact[_] =>
      (that canEqual this) &&
        name == that.name &&
        value == that.value
    case _ => false
  }

  override def hashCode(): Int = {
    val state = Seq(name, value)
    state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b)
  }

  override def toString = s"Fact(name=$name, value=$value)"

}

case object Fact {

  implicit val factEq: Eq[Fact[_]] = Eq.fromUniversalEquals[Fact[_]] // Neither of this works

//  implicit def factEq: Eq[Fact[_]] = new Eq[Fact[_]] {
//    def eqv(x: Fact[_], y: Fact[_]): Boolean = (x != null, y != null) match {
//      case (true, _)  => x.equals(y)
//      case (_, true)  => y.equals(x)
//      case _          => true
//    }
//  }

  implicit def factShow[T]: Show[Fact[T]] = (t: Fact[T]) => t.toString // Example calls for 'implicit val factShow[Fact[_]]' but that doesn't work

}

And the big surprise:

package org.hudelundpfusch.utilites.decisions

import cats._
import cats.data._
import cats.syntax._
import cats.implicits._
import cats.implicits.eq
import com.typesafe.scalalogging.LazyLogging
import org.hudelundpfusch.utilites.decisions.data.Fact
import org.hudelundpfusch.utilites.decisions.data.Fact._
// Tried to import everything that came to my mind to make the stuff working

object Fuddel
  extends App
    with LazyLogging {

  logger.info("Let's start to fuddel!")
  this.fuddel()
  logger.info("Enough with fuddling!")

  def fuddel(): Unit = {
    val fact1: Fact[String] = Fact[String]("FactName", "FactValue")
    println(s"${fact1.show}")
    val fact2: Fact[String] = Fact[String]("FactName", "FactValue")
    println(s"${fact2.show}")

    println(s"${fact1.equals(fact2)}")
    println(s"${fact1 == fact2}")
//    println(s"${fact1 === fact2}") // Not resolved...According to the repl example this should work with implicits imported
    println(s"${fact1 eq fact2}") // False? Oh joy! Thanks to the great repl example!
  }

}

So please, is there any documentation not beeing worthless?

Thanks in advance

Have a better day than me

Alex

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
  • 1
    I empathize with your frustration, but I doubt that you'd get useful answers for this question. Generally speaking, StackOverflow is great for specific answers to specific code issues, but is not designed to provide answers to "give me better documentation" requests. – Tzach Zohar Apr 09 '19 at 21:29

1 Answers1

4

1. This here compiles just fine (I removed your package name and logging dependency):

import cats.Show
import cats.kernel.Eq

case class Fact[+T](name: String, value: T) extends Equals {

  override def canEqual(that: Any): Boolean = that match {
    case _: Fact[_] => true
    case _          => false
  }

  override def equals(other: Any): Boolean = other match {
    case that: Fact[_] => true // TODO: replaced, irrelevant
    case _ => false
  }

  override def hashCode(): Int = {
    val state = Seq(name, value)
    state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b)
  }

  override def toString = s"Fact(name=$name, value=$value)"
}

case object Fact {
  implicit def factEq[A]: Eq[Fact[A]] = Eq.fromUniversalEquals[Fact[A]]
  implicit def factShow[T]: Show[Fact[T]] = (t: Fact[T]) => t.toString
}

Note the universal quantification instead of wildcard in factEq[A]. Then in Fuddel.scala:

import cats.syntax.show._
import cats.syntax.eq._
import Fact._

object Fuddel
  extends App {

  this.fuddel()

  def fuddel(): Unit = {
    val fact1: Fact[String] = Fact[String]("FactName", "FactValue")
    println(s"${fact1.show}")
    val fact2: Fact[String] = Fact[String]("FactName", "FactValue")
    println(s"${fact2.show}")

    println(s"${fact1.equals(fact2)}")
    println(s"${fact1 == fact2}")
    println(s"${fact1 === fact2}")
    println(s"${fact1 eq fact2}")// must be false, different instances
  }

}

Note that the eq is a method that is available on every object in Scala, there is no way to override it.


2. I'd recommend to read Welsh, Gurnell "Scala with Cats". Scaladoc is good too, but you cannot navigate it effectively until you read the introductory chapter about the organization of packages and implicits in the cats library.

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
  • Hello Andrey Thanks again. I'm just wondering if it's worth to keep trying. I've never seen a language that geve me so much trouble finding usable documentation. Have a nice evening Best regards Alex – Alexander Schell Apr 10 '19 at 19:03
  • I found it worthwhile. I currently cannot offer a language that is better integrated with all the ct-inspired stuff. If I had such a language, I'd share it. I don't feel like I'm in the right position for criticizing someone else's documentation efforts. – Andrey Tyukin Apr 11 '19 at 00:30