Reputation: 125
Running the following script under scala 2.10.4. I was expecting the result of a.classOp should be MyPage. Why it is nothing?
scala> trait PageModel {
| def classOp[T](implicit manifest: Manifest[T]) {
| println("Class: " + manifest.runtimeClass.getName)
| }
| }
defined trait PageModel
scala> class MyPage extends PageModel
defined class MyPage
scala> val a = new MyPage
a: MyPage = MyPage@1f2f992
scala> a.classOp
Class: scala.runtime.Nothing$
Edited:
I think I get the answer. Thanks! However, it is very interesting that the same code running on 2.9.3 gives me a java.lang.Object. Should it behave the same? I see NoManifest in 2.9.3 as well.
scala> trait PageModel{
| def classOp[T](implicit m: Manifest[T]) {
| println("Class: " + manifest[T].erasure.getName)
| }
| }
defined trait PageModel
scala> class MyPage extends PageModel
defined class MyPage
scala> val a = new MyPage
a: MyPage = MyPage@f7bf869
scala> a.classOp
Class: java.lang.Object
Upvotes: 0
Views: 114
Reputation: 4966
When you define this method def classOp[T](...)
what is T
constrained to? It can essentially be anything, so you're requesting an implicit manifest for a type T
that can be anything: implicit manifest: Manifest[T]
.
If you look in scala.Predef
you can see the following declaration:
val NoManifest = scala.reflect.NoManifest
Where NoManifest
is:
object NoManifest extends OptManifest[Nothing]
And where OptManifest
is:
/** A `OptManifest[T]` is an optional [[scala.reflect.Manifest]].
* It is either a `Manifest` or the value `NoManifest`.
So what does all this translate to?
Since Nothing
is the subtype of all types and there is always a Manifest[Nothing]
in scope (Predef
is always in scope) it will mean that this implicit will be injected when nothing else is found.
With this said, I agree with Ryan and you probably meant to do:
trait PageModel[T] {
def classOp(implicit manifest: Manifest[T]) {
println("Class: " + manifest.runtimeClass.getName)
}
}
Upvotes: 4
Reputation: 7257
I think you meant to parameterize PageModel
on its subclass, since right now a.classOp
doesn't have anything to fill in T
with so the compiler goes for the bottom type, Nothing
.
For instance:
scala> a.classOp[String]
java.lang.String
I'm assuming you were hoping to get the class name of MyPage
. In that case, you need to parameterize PageModel
on its subtype:
trait PageModel[T] {
def classOp(implicit manifest: Manifest[T]) =
println("Class: " + manifest.runtimeClass.getName)
}
class MyPage extends PageModel[MyPage]
val a = new MyPage
a.classOp // prints "Class: $line11.$read$$iw$$iw$MyPageModel"
Obviously outside the REPL classOp
would print a more readable FQCN.
Upvotes: 1