Scala Map indexed by Type -


i'm trying make set-like accepts 1 entry each subtype of trait. code currently:

import scala.reflect.classtag  trait component case class entity(id: int)  case class componenta(some: string) extends component case class componentb(other: int) extends component case class componentc(thing: boolean) extends component  val components: map[entity, set[component]] = map(entity(1) -> set(componenta("a"), componentb(1))) def getcomponent[a <: component: classtag](entity: entity): option[a] = {   components.getorelse(entity, nil).collectfirst { case c: => c } }  getcomponent[componenta](entity(1)) getcomponent[componentb](entity(1)) getcomponent[componentc](entity(1)) 

my list of entities in millions, components each entity ~100. there faster way, type indexed map, prevent o(n) collectfirst on every read, , filter + append each update?

i tried number of things, closest create componenttype trait used map[componenttype, component] key, , have getcomponent method return generic component instead of actual requested type. leaves me type cast @ runtime or pattern match each caller instead of have compiler cast me.

any other combinations types, enumerations, maybe specialized set or map type can here?

maybe type checking not worth overhead of doing 100/2 iterations on average, have nothing compare performance against.

you can avoid creating componenttype trait using map[classtag[_], component] second level structure:

val components: map[entity, map[classtag[_], component]] = map(   entity(1) -> map(     implicitly[classtag[componenta]] -> componenta("a"),      implicitly[classtag[componentb]] -> componentb(1)) )  def getcomponent[a <: component](entity: entity)(implicit tag: classtag[a]): option[a] = {   components.getorelse(entity, map[classtag[_], component]()).get(tag).asinstanceof[option[a]] } 

the same way can implement addcomponent:

def addcomponent[a <: component](entity: entity, component: a)(implicit tag: classtag[a]): map[entity, map[classtag[_], component]] = {   components + (entity -> (components.getorelse(entity, map[classtag[_], component]()) + (tag -> component))) } 

you not avoid casting way, if hide implementation of components map in class components, can pretty safe think:

class components {   private val components: map[entity, map[classtag[_], component]] = map()   def getcomponent[a <: component](entity: entity)(implicit tag: classtag[a]): option[a] = ???   def addcomponent[a <: component](entity: entity, component: a)(implicit tag: classtag[a]): components = ??? } 

update: based on @rüdigerklaehn's comment, modified code, it's more readable now:

val components: map[(entity, classtag[_]), component] = map(   (entity(1), implicitly[classtag[componenta]]) -> componenta("a"),   (entity(1), implicitly[classtag[componentb]]) -> componentb(1) )  def getcomponent[a <: component](entity: entity)(implicit tag: classtag[a]): option[a] = {   components.get((entity, tag)).asinstanceof[option[a]] }  def addcomponent[a <: component](entity: entity, component: a)(implicit tag: classtag[a]): map[(entity, classtag[_]), component] = {   components + ((entity, tag) -> component) } 

Comments