What consideration is there to add some compile-time reflection to eliminate the overhead of reflection at runtime?
For example, currently, Kotlin 1.4 intends to optimize out any KProperty
that would be generated for delegation methods like Lazy
’s getValue
, which doesn’t use the KPropery
parameter. We could go further and replace any use of property.name
with the property’s name, which should be known at compilation time, to eliminate the need for a reflection call.
We could go further and inline the getters and setters on a KProperty
as well. swap(::a, ::b)
could be an inline method:
private inline fun <T> swap(a: KMutableProperty0<T>, b: KMutableProperty0<T>) {
val temp = a.get()
a.set(b.get())
b.set(temp)
}
as if swap
actually took as arguments the two get
s and set
s, and inlined them together.
Finally, we could inline iterating over properties, as would be common in most serialization frameworks:
inline fun <reified T : Any> T.toJson() : String {
return T::class.memberProperties
.filter { it.javaField != null }
.joinToString(prefix = "{", postfix = "}", separator = ", ") { property ->
'"' + property.name + "\": " + when (property.returnType) {
String::class, Character::class -> "\"" + property.get(this) + "\""
Number::class, Boolean::class -> property.get(this)
else -> property.get(this).toJson()
}
}
}
This would require a few more concepts:
- An inlined list, that supports a few methods at compilation time so that each element is inlined into each operator (like loop unrolling) so that they can be optimized (which would be a useful feature in its own right)
- Optimizing a
when
statement when the class argument is known at compilation time - A convenient syntax for the above
when
statement to useNumber::class
to include all subtypes (asInt::class
isn’t equal toNumber::class
, but it shouldn’t be necessary to list every subclass) - Support for recursive calls to inline methods. This would probably require that each method not be actually inlined, but instead just reified to the specific type. That way, if someone were to serialize a large data structure, it wouldn’t repeat the serialization code for each type it encounters everywhere it is encountered, and it would be possible for a data structure to potentially contain itself and still be serializable.
To my knowledge, the only current way to do something like the above is to write either a compiler plugin (which isn’t nearly as portable, and is complicated) or an annotation processor (which has a high engineering overhead, it would take an order of magnitude or two more code to write an annotation processor that generates a class that does the same thing as toJson
for each annotated class, and then anyone using an IDE will have error messages until they fully compile their project).