简体   繁体   中英

scala implicit parameter type inference

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

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)
 }
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM