Остается ли тело inline функции в байткоде JVM или полностью встраивается
Что проверяют
Понимаете ли вы, что inline в Kotlin делает на самом деле, или запомнили формулировку «убирает накладные расходы на вызов». Вопрос задан как выбор из двух вариантов, а верный ответ «и то, и другое», и это сразу отделяет заученное от понятого.
Как отвечать
Тело копируется в каждое место вызова, и при этом в классе остаётся обычный метод с тем же телом. Он нужен, чтобы функцию можно было вызвать из Java, где никакой подстановки не будет, и чтобы её могли встроить модули, компилируемые отдельно и видящие только байткод.
Дальше объясните смысл. Главный выигрыш не в устранении вызова: виртуальная машина сама встраивает мелкие методы. Выигрыш в том, что лямбда-параметр не превращается в объект. Без inline каждая переданная лямбда это экземпляр класса функции с захваченными переменными в полях, а в горячем цикле это заметная нагрузка на память. Отсюда же две возможности, ради которых inline чаще всего и ставят: нелокальный return из лямбды и параметр типа с reified, который иначе невозможен из-за стирания типов.
Упомяните соседние ключевые слова: noinline, если лямбду надо сохранить или передать дальше, и crossinline, если она вызывается из другого контекста и нелокальный выход надо запретить.
inline fun <reified T : Activity> Context.open() =
startActivity(Intent(this, T::class.java))Где спотыкаются
Говорят, что компилятор сам решает, встраивать или нет, и слишком большую функцию пропустит. Это указание, а не пожелание: тело подставится в любом случае. Компилятор ведёт себя ровно наоборот, он предупреждает, что на функции без лямбда-параметров выигрыша ждать не стоит.
Ставят inline подряд на всё. Каждый вызов это копия тела: растёт размер собранного кода, а раздутый метод виртуальная машина уже не встроит, и результат получается обратный задуманному.
Забывают про ограничения публичной inline-функции. Она не может трогать приватные члены, потому что её тело окажется в чужом классе, и приходится помечать вспомогательный код как @PublishedApi internal. Там же лежит проблема совместимости: изменили тело, а у всех, кто уже собрался со старой копией, останется старое поведение до пересборки.