не могу объяснить такое поведение, как ниже.
Может кто-то поможет?
import kotlin.reflect.KType
fun main() {
println(object : KTypeToken<List<*>>() {}.type)
println(typeOf<List<*>>())
}
abstract class KTypeToken<T> {
val type: KType = this::class.supertypes.first { it.classifier == KTypeToken::class }.arguments[0].type!!
}
inline fun <reified T> typeOf(): KType = object : KTypeToken<T>() {}.type
Выводит
kotlin.collections.List<*>
[ERROR : Unknown type parameter 0. Please try recompiling module containing "[container not found]"]
А причём тут реификация? То, что ошибка странно, но там ведь даже она не используется вроде
Нет, она используется в функции typeOf для параметра T
Так оно и без reified скомпилится
Да, компилится, но что-то не работает :(
Та же ошибка? А без inline тоже не работает?
Так-то не должно 🤔
Без inline и не будет 100%. Там же трюк с анонимным наследником KTypeToken, чтобы сохранить в рантайме информацию о типе, подставленном вместо T, который стирается. А если без inline и reified, то эта информация и не доедет до момента создания наследника, создастся как наследник сырого типа. Не понятно, почему с inline и reified не доезжает.
Почему? Насколько я знаю оно не скомпилится ток если T::class используется
Почему не должно?
я не знаю почему вы так долго это обсуждаете, reified сохраняет класс и не стирает его, но вы в typeOf его используете как дженерик класса, который в любом случае е может быть reified, так что то, что вы делаете в инлайн функции - бессмысленно.
Так здесь точно так же нужен конкретный тип
не бывает у классов reified дженериков
Сто раз так делал и всё работает
Мы же просто дженерик в класс передаём, это делали в джаве и без reified
Ну вообще да, он может и стереться
Ну он и сотрётся, я об этом с самого начала и говорю)
Может, это из-за wildcard?
В такой функции не должен
В функции нет, а в классе да
Нет: fun main() { println(object : KTypeToken<List<String>>() {}.type) println(kTypeOf<List<String>>()) } kotlin.collections.List<kotlin.String> [ERROR : Unknown type parameter 0. Please try recompiling module containing "[container not found]"]
И всё-таки попробуйте без inline
Пробовал уже. Тот же результат
Без inline вызов этой функции не будет приводить к созданию нового анонимного класса, в котором сохранится информация о типе
Так если оно и без inline и с inline не работает, то в данном случае это не важно, я просто локализирую проблему
предполагаю что нужно иссью, не подумали, что так будут использовать
Там проблема только с самой функцией, а не с inline или reified
нет, проблема с тем, что reified типы не доезжают до анонимных наследников
Этот трюк не работает. Сохраняйте T::class.
И как мне T::class поможет сохранить в рантайме полную информацию о типе List<String>?
А как оно тогда там работает? https://t.me/kotlin_lang/223602
и что даже иссью не надо писать, не сделать это никак?
И да, сам трюк с анонимным классом, прекрасно работает. А вот inline reified функция на его основе - нет
Через сохранение типа и передачи его же в родителя. Очень хитро сделано: https://github.com/FasterXML/jackson-core/blob/9e33b3a5b53c7bce13ae2a00dcf097fcab919969/src/main/java/com/fasterxml/jackson/core/type/TypeReference.java
Ну так и я то же самое делаю
Ну внутри там всё хитро, конечно. Но как это связано с тем, что в одном случае компилятор создаёт классы с конкретным типом для каждого вызова инлайн-функции, а в другом - нет?
Ишью надо делать. По идее, это баг в kotlin.reflect, так как в джавовом рефлекшне всё работает.
Это не в рефлекшене проблема
Ну ХЗ. До ввода typeOf, официальный workaround использовал джавовый рефлекшн: https://gist.github.com/udalov/bb6f398c2e643ee69586356fdd67e9b1. А то, что reified T не передаётся в класс - это логично, если учесть, что инлайнер работает на байткоде, а там уже java.lang.Object вместо T.
В одном он вкомпиливает нужный тип сразу, а в другом - через байткод, к котором T уже стирается.
Да, похоже бага в kotlin.reflection. Если написать аналогичный код для java.reflection, то reified inline работает
Обсуждают сегодня