Generics и inline без магии
in/out, стирание типов, reified и нелокальный return
Кто производит, кто потребляет
out T разрешает использовать производителя более конкретного типа там, где ждут более общий. in T делает безопасным обратное направление для потребителя. MutableList<T> инвариантен: иначе в список строк можно было бы записать число. Звёздочка * означает неизвестный параметр с безопасными ограничениями, а не Any? для произвольной записи. Kotlin: generics.
interface Source<out T> { fun get(): T }
interface Sink<in T> { fun put(value: T) }
fun read(source: Source<Number>): Number = source.get()
Что даёт inline
Встраивание может убрать вызов переданной лямбды и позволяет нелокальный return там, где лямбда встраивается непосредственно. noinline оставляет параметр обычным значением функции; crossinline запрещает нелокальный выход, когда лямбду вызывают в другом контексте. Это не обещание ускорения каждого вызова. Kotlin: inline.
Граница reified
На JVM обычные параметры generic-типов стираются. inline reified разрешает проверку value is T, но не восстанавливает параметры вложенных объектов: проверка List<String> не доказывает, что каждый элемент — строка. На границе недоверенных данных проверяйте элементы или декодируйте их по схеме. Kotlin: generics.
inline fun <reified T> firstOf(values: List<Any?>): T? =
values.firstOrNull { it is T } as T?
Пример рассчитан на проверяемый тип вроде String, не на доказательство содержимого List<String>.
Основа отбора: draft/kotlin_base.md, draft/M++.md.