How do you compare two objects and require them to be of the same type?

I find it very common mistake to compare two objects of different types, for example.

case class User(name:Option[String])

val user = User(Some("Freewind"))

if(user.name == "Freewind") { // never be true!!!
    ...
}

      

If there is a way to compare two objects, requiring them to be of the same type?

+3


source to share


3 answers


So, strictly speaking, the "variable type" is always present and can be passed as a type parameter. For example:

val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x

      

But depending on what you want to do, it won't help you. For example, you may not know what the type of a variable is, but know if the type of the value is a specific type, for example:

val x: Any = 5
def f[T](v: T) = v match {
  case _: Int    => "Int"
  case _: String => "String"
  case _         => "Unknown"
}
f(x)

      

It doesn't matter what the type of the variable Any is. It is important that type 5, value is checked. Actually, T is useless - you could also write it def f (v: Any). Also, this uses the ClassTag or the Value class, which are explained below, and cannot check type type parameters: you can check if something is List [_] (List of something), but if it is not for eg List [Int] or List [String].

Another possibility is that you want to confirm the type of the variable. That is, you want to convert the type to a value so that you can store it, pass it, etc. This includes reflection and you will be using either ClassTag or TypeTag. For example:

val x: Any = 5
import scala.reflect.ClassTag
def f[T](v: T)(implicit ev: ClassTag[T]) = ev.toString
f(x) // returns the string "Any"

      

The ClassTag will also allow you to use the type parameters that you match. It won't work:

def f[A, B](a: A, b: B) = a match {
  case _: B => "A is a B"
  case _ => "A is not a B"
}

      

But it will:

val x: Any = 5
val y = 5
import scala.reflect.ClassTag
def f[A, B: ClassTag](a: A, b: B) = a match {
  case _: B => "A is a B"
  case _ => "A is not a B"
}
f(x, y) // A (Any) is not a B (Int)
f(y, x) // A (Int) is a B (Any)

      



Here I am using the context bounds syntax, B: ClassTag, which works exactly like the implicit parameter in the previous ClassTag example, but uses an anonymous variable.

You can also get the ClassTag from the value class, for example:

val x: Any = 5
val y = 5
import scala.reflect.ClassTag
def f(a: Any, b: Any) = {
  val B = ClassTag(b.getClass)
  ClassTag(a.getClass) match {
    case B => "a is the same class as b"
    case _ => "a is not the same class as b"
  }
}
f(x, y) == f(y, x) // true, a is the same class as b

      

ClassTag is limited in that it only covers the base class, not the type. That is, the ClassTag for List [Int] and List [String] is the same as List. If you need type parameters, then you should use TypeTag instead. However, the TypeTag cannot be derived from the value and cannot be used for pattern matching due to JVM erasure.

Examples with TypeTag can be quite tricky - even comparing two type tags is not straightforward, as shown below:

import scala.reflect.runtime.universe.TypeTag
def f[A, B](a: A, b: B)(implicit evA: TypeTag[A], evB: TypeTag[B]) = evA == evB
type X = Int
val x: X = 5
val y = 5
f(x, y) // false, X is not the same type as Int

      

Of course, there are ways to make this comparison correct, but it will take several chapters of the book to really cover TypeTag, so I'll stop here.

Finally, maybe you don't need the type of the variable at all. Perhaps you just want to know what the value class is, in which case the answer is pretty simple:

val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it

      

It would be better, however, to be more specific about what you want to achieve so that the answer can be more accurate.

+4


source


You cannot actually do it with an operator ==

, as it is similar to a Java method Object.equals

. Scalaz actually solves this problem by constructing a new operator ===

. Take a look at: scalaz.syntax.EqualOps



+1


source


Scalaz is of type class Equal

( Scalaz training examples ). Also, I noticed that sometimes when scanning for unrelated types, the scalar generates a warning, but it seems buggy .

+1


source







All Articles