2

The following code

def httpPost[T: ClassManifest](data: AnyRef): T = {
  val webResource = client.resource("http://localhost..")
  val resp = webResource.post(classOf[ClientResponse], data)
  resp.getEntity(classManifest[T].erasure) //Need classOf[T] here 
}

results in this type mismatch compilation error

[INFO]  found   : _$1 where type _$1
[INFO]  required: T
[INFO]       resp.getEntity(classManifest[T].erasure)

Based on the answer to Scala classOf for type parameter it looks like it should work.

The erasure method returns java.lang.Class[_] and I presume that this is the problem so I have two questions:

  • Why does the class manifest return an existential type and not simply Class[T] - if it's the erasure of T, surely that will always be _ (underscore) because T is obviously unknown, which means its return value isn't as useful as I'd have expected.
  • What do I need to do to make the code work!

Update:

Thanks Kim and Jean-Phillipe for your answers.

I had previously tried a cast so the original last line was replaced with

val responseData = resp.getEntity(classManifest[T].erasure) //Runtime error
responseData.asInstanceOf[T]

and this compiles but there's now a runtime error because the getEntity method is passed the class of Object, which it can't process because it needs a more specific type (for which it has a handler). Although it's deferred until runtime, it again comes down to the erasure method not giving specific type information and that's why I thought that to solve the problem, the inline example must be solved.

Community
  • 1
  • 1
Dextaa
  • 65
  • 5

3 Answers3

2

There's something seriously wrong with this code. In particular:

def httpPost[T: ClassManifest](data: AnyRef): T = {
  val webResource = client.resource("http://localhost..")
  val resp = webResource.post(classOf[ClientResponse], data)
  resp.getEntity(classManifest[T].erasure) //Need classOf[T] here 
}

How is Scala supposed to know what the type of T is? Are you passing it explicitly when invoking httpPost? I suspect not, and that's the reason why erasure is returning Object for you.

As for why ClassManifest#erasure returns Class[_] instead of something else, I suspect the reason is that this is the type used by most Java methods, and since Class is invariant, if erasure returned Class[T], then you'd have to cast it to use it with those methods!

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • Thanks for for your comments. There's nothing wrong with the code as per my original update (about the cast). However, I wasn't using a type parameter at the invocation site - I thought that it would be inferred from the assignment target. It worked with that addition. – Dextaa Jun 20 '11 at 09:23
0

First question: No idea...

Second question: I think it is safe to cast here. You can use foo.asInstanceOf[Class[T]].

Kim Stebel
  • 41,826
  • 12
  • 125
  • 142
0

I believe that an existential type is returned to make it clear that the cast that you may want to make is your responsibility. Class is a bit weird: for instance, a Class[List[String]] should actually be typed as a Class[List[_]] as it does not carry any information about the String parametrization of List. The cast suggested by Kim is always safe when T is not itself a parametrized type.

Jean-Philippe Pellet
  • 59,296
  • 21
  • 173
  • 234