Suppose I want every instance of an Item
to be a SourceOf
that Item
, and every SourceOf
a subtype of Item
to be a SourceOf
all instances of that subtype. This seems like a natural way to do it:
object Demo {
trait Item extends SourceOf[this.type]
trait SourceOf[+A <: Item]
}
Obviously this won't work, since this
refers to the Demo
object, not to each Item
instance. (I've tested it.)
How can I tell the Scala compiler that every Item
is a source of itself? It should be possible to get the compiler to deduce stuff like:
"Every source of (all) farming implements is a source of the specific farming implement you're looking for."
"If you're looking for the source of a farming implement, and you already have the farming implement, then you need look no further."
Here's an example (written to ignore type erasure for brevity):
trait FarmingImplement extends Item
object TheRototiller extends FarmingImplement
def findSource(item: Item, seq: Seq[SourceOf[_]]): Option[SourceOf[item.type]] =
seq.collectFirst {
case src: SourceOf[item.type] => src
}
val sources = Seq( // example: possible sources of TheRototiller
new SourceOf[Nothing] { override def toString = "Wrong source" },
new SourceOf[FarmingImplement] { override def toString = "Right" },
TheRototiller /* also right */ )
val got = findSource(TheRototiller, sources).get
println(got) // Should print "Right", since the second source in `sources`
// is the first match.
I want the type of got
be SourceOf[TheRototiller.type]
, not SourceOf[Item]
. But mainly I want Scala's type system to do the work of determining whether a SourceOf
matches a given Item
or category of Items
.
At least, this gonna solve your problem with passing
this
:Example (you'll have to compare
T
s instead ofSourceOf
s here):If you need to check types in runtime (as you've shown in example with pattern matching) - I would recomend to use
TypeTag
:Usage:
Finally, implementation of
findSource
:Examples:
asInstanceOf
is used (it's safe to do here) becauseSeq
looses path-dependent type in compile-time and we used runtime-check to match types, so no way to find it for compiler. However, Shapeless2'sHList
+Selector
based implementation might be more pure.