Class Literals

As a learning exercise, I am porting an existing project from statically typed Groovy to Kotlin.

I am struggling to translate the following idiom:

@CompileStatic class Entity {   private final Map<Class<? extends Facet>, Facet> facets = [:]

  public LogEntity addFacet(Facet facet) {
  def type = facet.getClass() as Class<? extends Facet>
  facets[type] = facet
  return this
  }

  public <T extends Facet> T facet(Class<T> facetType) {
  def f = facets[facetType]
  return facetType.cast(f) as T // TODO: GROOVY-5891
  }
}

// usage def e = new Entity() s.addFacet(new SomeData(x: 123, y: 345, ...)) s.addFacet(new SomeOtherData(a: 'abc', b: 123...)) ....

assert e.facet(SomeData)?.x==123 && e.facet(SomeOtherData)?.a==‘abc’


And in Kotlin:

class Entity() {   val facets : MutableMap<Class<Facet>, Facet> = hashMapOf()

  fun setFacet(facet: Facet) : LogEntity {
  facets[facet.javaClass] = facet
  return this
  }

  fun <T: Facet> facet(facet: Class<T>) : T? {
  return facet.cast(facets[facet])
  }
}

// usage

val e = Entity()
s.addFacet(SomeData(123, 345, …)) // can we have named arguments?
s.addFacet(SomeOtherData(‘abc’, 123…))

e.facet( ??? )

What we achieve that an entity can contain multiple facets and we can query for them and dereference them in typesafe manner, with autocompletion, etc.

I have hit a roadblock when I tried to use it and realized that I can not use class-literals in Kotlin…

Please let me know if there is some other more idiomatic way of achieving similar objective.

There is javaClass<T>() function which substitutes class literal expression. Here is usage for your example:

``

e.facet(javaClass<SomeData>())

P. S. Yes, there are named arguments in Kotlin, see corresponding docs article.

Thanks, I wouldn't have thought - does this mean that templates are reified?

Can I write a function myself that has access to its (possibly inferred) generic params?

No, they are not reified. Reified generics can be implemented for JVM only with big performance overhead, and we decided to cancel this feature.

javaClass() is a special function which is kind of reified, but not exactly. When it is called with concrete class as type argument, it is compiled to analog of java’s “.class” expression. But you can’t call it with another type parameter as type argument (e.g., javaClass<T>()). Just now it will compile, but it’s incorrect, and will provoke compilation error later.

1 Like