In Scala 2.9.1
With
def collectFirstOfT[T](la: List[_])(implicit m:Manifest[T]) : Option[T] = {
la.collect{case x if m.erasure.isAssignableFrom(x.getClass) => x}.
headOption.asInstanceOf[Option[T]]}
class A
class B
why this expression :
val oB:Option[B] = collectFirstOf(List(new A,new B))
compiles but collects Some(A),but
val oB =collectFirstOf[B](List(new A,new B))
works fine.
How to infer T from Option[T] ?
You have to look at the following line as two separate parts, the left hand side of the = and the right:
val oB: Option[B] = collectFirstOf(List(new A,new B))
What you're expecting here is that the type of the collectFirstOf expression (the rvalue) should be inferred from the type of the value oB. The compiler can't do this. You have to say specifically what type you're expecting. Take the following example:
val v: Long = 1 + 4
The type of the expression 1 + 4 is an Int. This int is then converted into a Long. The compiler doesn't, and can't infer that you want the 1 or the 4 to be Long:
So, to fix your problem, you need to tell the compiler what type you're expecting, otherwise it assumes java.lang.Object:
val oB = collectFirstOf[B](List(new A,new B))
So the manifest gets correctly assigned, and all is well with the world. So why does the following even compile:
val oB:Option[B] = collectFirstOfT(List(new A,new B))
oB: Option[B] = Some(A@10f3a9c)
at first sight, it doesn't seem like this should work, but it does. This is because the collectFirstOfT actually returns an Option[Nothing], which can be safely converted to a Option[B]:
scala> val f = collectFirstOfT(List(new A,new B))
f: Option[Nothing] = Some(A@baecb8)
scala> f.asInstanceOf[Option[B]]
res4: Option[B] = Some(A@baecb8)
This:
val oB:Option[B] = collectFirstOfT(List(new A,new B))
Is equivalent to this:
val oB:Option[B] = collectFirstOfT[Nothing](List(new A,new B))
Since Nothing
is a subclass of everything, then it is assignable from A
. Alas, it is also assignable from B
, which means you can assign an Option[Nothing]
to an Option[B]
.
Fun fact: that is true because Option
is co-variant. If it wasn't, then T
would have to be inferred as B
, which would make it work.
Fun fact 2: this code does not compile on yesterday's trunk.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With