scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

getClass() return java.lang.Class[T] forSome { val T : C } #490

Closed scabug closed 13 years ago

scabug commented 16 years ago

It would be useful if Scala were to treat the return from getClass() as a java.lang.Class[T] forSome { val T : C } where C is something like the erasure of the static type of the expression on which getClass is called. This would match Java 6:

http://java.sun.com/javase/6/docs/api/java/lang/Object.html#getClass()

It would let me do something like the following where I want to introspect on a class but shouldn't need a class instance. I also want to limit the types of classes I want to introspect on, so I use Class[_ <: Foo]. But this prevents me from passing in a Foo class by using Foo.getClass() without a cast.

trait IdlBase

class IdlConcrete

object Test extends Application {
  // In general, this method should not need an instance to reflect on it, so
  // take a Class[]
  def reflect(clazz : Class[_ <: IdlBase]) = {
    // Get a list of all its methods and build a hash keyed by method name
    // for statistics recording.
  }

  // But I also really have an IdlConcrete generated by Spring here...
  val idl = new IdlConcrete
  reflect(idl.getClass)
}
test.scala:14: error: type mismatch;
 found   : java.lang.Class[?0] where type ?0
 required: Class[_$$1] forSome { type _$$1 <: IdlBase }
  reflect(idl.getClass)
              ^
one error found

There was a request for this and Martin responded:

http://scala-programming-language.1934581.n4.nabble.com/Java-generics-vs-Scala-types-td1937960.html

scabug commented 16 years ago

Imported From: https://issues.scala-lang.org/browse/SI-490?orig=1 Reporter: @blair

scabug commented 16 years ago

@SethTisue said: I find I am hitting this issue in my own code. +1 on an eventual fix; Scala has taken a step backward from Java in this respect.

scabug commented 16 years ago

Lauri Alanko (lealanko) said: There is a similar issue for classOf[]. Whereas the type of getClass() is currently too weak, the type of classOf[] is too strong:

scala> classOf[List[int]]
res4: java.lang.Class[List[int]] = class scala.List

scala> classOf[List[String]]
res5: java.lang.Class[List[String]] = class scala.List

That is, the type system claims that the class object is a representation of a type application, even though there is no real run-time information about the type argument.

I think it would be desirable for the property to hold that if (a : Class[A]) eq (b : Class[B]), then A <: B <: A. This is not currently true.

So I suggest that classOf gets the same treatment as is suggested for getClass: let the type of classOf[A] be Class[B] where B is the "existential erasure" of A (or whatever is the upper bound of all types that share the erasure of A), i.e.:

classOf[List[A]] : Class[List[T] forSome { type T }]
scabug commented 13 years ago

@SethTisue said: see also #4696

scabug commented 13 years ago

Commit Message Bot (anonymous) said: (extempore in r25137) A total rewrite of "runtimeClass", discarding the user-space approach in favor of simply fixing getClass.

def f1 = 5.getClass // Class[Int] def f2 = (5: AnyVal).getClass // Class[ <: AnyVal] def f3 = (5: java.lang.Integer).getClass // Class[ <: java.lang.Integer]

class A class B extends A

def f1 = (new B: Any).getClass().newInstance() // Any def f2 = (new B: AnyRef).getClass().newInstance() // AnyRef def f3 = (new B: A).getClass().newInstance() // A def f4 = (new B: B).getClass().newInstance() // B

But that's not all!

def f0[T >: B] = (new B: T).getClass().newInstance()

def f5 = f0[Any] // Any def f6 = f0[AnyRef] // AnyRef def f7 = f0[A] // A def f8 = f0[B] // B

Closes #490, #896, #4696. Review by moors. (Note: I think this is pretty good, but picky review requested.)