Как стать автором
Обновить

Комментарии 10

Спасибо за статью и подробное объяснение!

Добавлю небольшое уточнение по поводу crossinline.

    private inline fun crossInlineFun(crossinline body: () -> String) {
        val func = {
            "crossInline func code, " + body.invoke()
        }
        regularFun(func)
    }

В этом примере нужен crossinline, так как в передаваемой лямбде-параметре body на стороне вызывающей функции могут быть non-local returns, и поэтому body нельзя передавать в другой контекст исполнения (в лямбду func). Чтобы исправить это, можно либо отменить инлайнинг body (добавив noinline), либо запретив использовать non-local returns внутри body (добавив crossinline). В этом примере более предпочтителен вариант с crossinline, так как он позволяет всё-таки заинлайнить body.

noinline же полезен в том случае, когда, например, нужно работать с лямбдой-параметром в inline функции как с обычной переменной или передать в качестве параметра в "не inline" функцию.

    private inline fun crossInlineFun(noinline body: () -> String) {
        val someFunc = body
        regularFun(func)
    }

Здесь отменяется илнайнинг body, поэтому для него создаётся инстанс анонимного класса, и с ним можно работать как с обычной переменной.

Спасибо за уточнение, я поэкспериментирую с этим и возможно поправлю статью. Это может быть важно и возможно я сам что то упустил.

Да, если бы не локальный return, то crossinline можно было бы применять автоматом

Этот пример очень хорошо показывает, что inline функции никак не помогают нам экономить количество методов.

Это неправда. Помогают, если включена минификация. Если инлайн-метод не используется из джавы, то он будет вырезан.

Не надо пытаться помогать JIT компилятору делать его работу)
Суть инлайнинга не в экономии методов. Косвенно он может их сокращать, но задуман он совсем не для этого.

Это никак не противоречит тому, что я сказал. Утверждение в статье от этого правдой не становится.

Вот честно, тезис о том, что inline экономит количество методов, только от вас услышал. Обычно говорят, что он уменьшает количество вызовов, что может быть хорошо в циклах.

Ну я регулярно слышу его на реальных собесах)

Лямбда аргументы inline функции прозрачны для контекстов suspend и @Composable

suspend fun test() = Unit

fun repeat1(i: Int, action: (Int) -> Unit): Unit = TODO()

suspend fun context() {
    repeat1(5) {
        test()
    }
}

Такой код с repeat без inline не скомпилируется, нужно чтобы было action: suspend (Int) -> Unit. А потом появляется Compose и нужна +1 перегрузка. С inline одна декларация работает сразу с любыми вызовами

Да, интересное решение. Кажется что отменяем строгую типизацию, но она просто переносится в место вызова функции.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории