Following my previous question came a quick and great answer, however it turned out my example didn’t match my actual production code well enough. In summary I’m in need of a new implementation of the collect method.
The second fruit world (with some pretty funky fruit trees):
class Fruit {
var seeds:Array[Fruit] = Array()
def naiveCollect[F <: Fruit]:Array[Fruit] = this match {
case f:F => Array(this)
case _ => seeds.map(_.select[F]).flatten.toArray
}
}
class Apple extends Fruit
class Pear extends Fruit
class GrannySmith extends Apple
Does not work because of type erasure:
var tree = new Fruit { seeds = Array(
new Apple,
new Pear,
new GrannySmith,
new Pear { seeds = Array(
new Apple,
new Pear)},
new Apple)}
scala> tree.naiveCollect[Apple]
res1: Array[Fruit] = Array($anon$2@5a4b99fa)
// wanted output: Apple, GrannySmith, Apple, Apple
EDIT, SOLUTION1:
Turns out i managed to produce something which works by using the PartialFunction as in the std lib.
class Fruit {
...
def clumsyCollect[F](pf:PartialFunction[Fruit, F]):Seq[F] =
if (pf.isDefinedAt(this))
List(pf(this))
else
seeds.flatMap(_.selectPartial[F](pf))
}
Use case:
tree.clumsyCollect { case a:Apple => a }
Any alternatives or tips on cleaning this up would still be great though!
I think what you need is
scala.reflect.ClassManifestWith every call of
selectan implicit parameter containing actual class information will be passed. You can now make class checks at runtime, and also you can returnArrayof more specific type.This produces desired result:
Alternatively, you can use context bound syntax: