This is just to show that @cmbaxter 's answer works as expected. I'll restate the initial code as well, so that it is fully executable:
// Attribute Interface
object Attribute {
trait Int [S] extends Attribute[S]
trait Boolean[S] extends Attribute[S] // etc.
}
sealed trait Attribute[S]
// Attribute Map Interface
trait Attributes[S] {
protected def get(key: String): Option[Attribute[S]]
def apply[A[_] <: Attribute[_]](key: String)
(implicit tag: reflect.ClassTag[A[S]]): Option[A[S]] =
get(key) match {
case Some(attr) => tag.unapply(attr)
case _ => None
}
}
}
// Test Case
class Test {
val map = new Attributes[Foo] {
def get(key: String) = key match {
case "foo" => Some(new Attribute.Int [Foo] { override def toString = "I" })
case "bar" => Some(new Attribute.Boolean[Foo] { override def toString = "B" })
case _ => None
}
}
println(s"An int attr named `foo`: ${map[Attribute.Int ]("foo")}")
println(s"A bool attr named `foo`: ${map[Attribute.Boolean]("foo")}")
println(s"An int attr named `bar`: ${map[Attribute.Int ]("bar")}")
println(s"A bool attr named `bar`: ${map[Attribute.Boolean]("bar")}")
println(s"An int attr named `???`: ${map[Attribute.Int ]("???")}")
println(s"A bool attr named `???`: ${map[Attribute.Boolean]("???")}")
}
// Running
new Test
An int attr named `foo`: Some(I)
A bool attr named `foo`: None
An int attr named `bar`: None
A bool attr named `bar`: Some(B)
An int attr named `???`: None
A bool attr named `???`: None