Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent TypeTag for String #9402

Closed
scabug opened this issue Jul 16, 2015 · 10 comments
Closed

Inconsistent TypeTag for String #9402

scabug opened this issue Jul 16, 2015 · 10 comments
Assignees

Comments

@scabug
Copy link

scabug commented Jul 16, 2015

When using an implicit TypeTag parameter, you get TypeTag[java.lang.String] for a string literal or type java.lang.String in a type application, but you get TypeTag[String] for the type String in a type application. These two type tags do not compare equal.

This is confusing, I expect the type application [String] to correspond to a string literal. Just like the type application [Int] corresponds to an integer literal.

import scala.reflect.runtime.universe.TypeTag

class TypedContainer[T] private (storedTag: TypeTag[T], value: T) {

  def apply[U](implicit tag: TypeTag[U], ev: T <:< U): U =
    if (tag == storedTag)
      value
    else
      throw new IllegalArgumentException(s"$tag != $storedTag")

}

object TypedContainer {
  def apply[T](x: T)(implicit tag: TypeTag[T]): TypedContainer[T] =
    new TypedContainer(tag, x)
}

object Main extends App {

  val s: TypedContainer[String] = TypedContainer("Foo")

  println(s[java.lang.String])  // works as expected
  println(s[String])            // run-time error, but should work
  // println(s[Int])            // compile error, as expected

}
@scabug
Copy link
Author

scabug commented Jul 16, 2015

Imported From: https://issues.scala-lang.org/browse/SI-9402?orig=1
Reporter: Mikael Ståldal (mikaelstaldal)
Affected Versions: 2.11.7

@scabug
Copy link
Author

scabug commented Jul 21, 2015

@retronym said:
Unfortunately types cannot be compares with ==, you need to use =:=. This means that you can't short circuit lookups in maps/sets with hashCode.

Runtime reflection can end up with different symbols to represent the same package, due to the way it models classloader heirarchies:

https://gist.github.com/retronym/0440cd94f6b531d0e5a0

@scabug scabug closed this as completed Jul 21, 2015
@scabug
Copy link
Author

scabug commented Jul 22, 2015

Mikael Ståldal (mikaelstaldal) said:
TypeTag is a class in the Scala standard library, it implements equals and hashCode. Why cannot these implementations be changed to have the same semantics as =:=? Something like this:

  trait TypeTag[T] extends WeakTypeTag[T] with Equals with Serializable {
    override def equals(x: Any) = x.isInstanceOf[TypeTag[_]] &&  this.tpe =:= x.asInstanceOf[TypeTag[_]].tpe
  }

@scabug
Copy link
Author

scabug commented Jul 22, 2015

@retronym said:
Unfortunately it is not possible to provide a useful implementation of hashCode that is coherent with that definition of equals, so we are reluctant to venture into this territory.

@scabug
Copy link
Author

scabug commented Jul 22, 2015

Mikael Ståldal (mikaelstaldal) said:
Ah, I see. Too bad, but that makes sense.

What about adding =:= directly to TypeTag?

trait TypeTag[T] extends WeakTypeTag[T] with Equals with Serializable {
  def =:= (that: Type) = this.tpe =:= that.tpe
}

@scabug
Copy link
Author

scabug commented Jul 23, 2015

Mikael Ståldal (mikaelstaldal) said:
Why do you get different TypeTags for [String] and a string literal in the first place?

@scabug
Copy link
Author

scabug commented Jul 24, 2015

Mikael Ståldal (mikaelstaldal) said:
Why does TypeTag implement Equals if that comparison is not useful?

@scabug
Copy link
Author

scabug commented Jul 24, 2015

@retronym said:
I think that is a hangover from an earlier design, in which TypeTag extended ErasureTag:

scala/scala@2b09d8c#diff-60210be5d1c8c7fc228f97c97d5a8941R125

@scabug
Copy link
Author

scabug commented Jul 24, 2015

@retronym said:
Actually, it is still needed as TypeTag extends WeakTypeTag.

The equals/ canEqual pattern does ensure coherent equality within the type heirarchy.

@scabug
Copy link
Author

scabug commented Aug 3, 2015

Mikael Ståldal (mikaelstaldal) said:
Is the equal comparison useful for {{WeakTypeTag}}? If not, why does {{WeakTypeTag}} implement {{Equals}}?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants