* — вопросы о компиляторе и генерируемом байт-коде
Классы
Что за тип такой — Unit? Зачем нужен?
Как компилируются object declarations и companion objects? *
Какая польза от typealias? Во что он компилируется? *
Зачем нужен тип Nothing, какие выражения имеют такой тип? Какие ограничения накладываются на Nothing?
Объекты
Когда компилятор использует примитивные типы? В каких случаях происходит автобоксинг? *
Какие объекты выделяются при вызове forEach, map, reduce, fold и т. п. на Iterable? на Sequence? *
Зачем вообще нужны Sequences?
Функции
Что такое функциональный тип, какие у него ограничения?
Как работают SAM-conversions? *
Что такое функции высшего порядка (higher-order functions), лямбда-выражения (lambda-expressions), анонимные функции (anonymous functions), указатели на методы (method references, bound callable references)?
Какой толк от inline-функций, как компилируется сама функция и места её использования? *
Как работают crossinline и noinline? *
Можно ли в лямбде изменить значение переменной, захваченной из внешней области видимости? Как это работает в inline-функциях? noinline-функциях? во многопоточном окружении?
Что использовать вместо try-with-resources?
Как компилируются default-методы в интерфейсах? *
Как компилируются extension-функции и как использовать их из Java?
Можно ли сделать extension к интерфейсу? Тайпалиасу? Функциональному типу?
Может ли функция быть одновременно member и extension? Как её использовать?
Выражения
Почему присваивания — не выражения (assignments are not expressions)?
Что такое exhaustive when, на каких типах он возможен?
Дженерики
Чем дженерики в Kotlin отличаются от джавовых?
Что такое declaration-site variance? Где помогает, где затрудняет разработку, как выглядит из Java?
Как устроен reified, почему работает только в inline-функциях? *
Как с помощью reified получить не сырой тип (класс), а параметризованный тип (parameterized type) со всеми его аргументами (actual type arguments)? *
Корутины
Зачем нужны корутины? Почему бы не наплодить обычных тредов?
Как устроена трансформация suspend-функций? *
Комментарии к статье
{"type":"articleComments","id":"498e4499-a446-4020-be68-30f7b5d67458","comments":[{"id":"b9d0fddf-0283-4181-81d0-9821d81fd7c4","authorSrc":"GitHub","authorId":"maxdoctorkurt","text":"\"Как компилируются ....\"\nВ каких задачах это знание используется, связанные ошибки и т. д.?\nВообще неплохо было бы описать в общем виде, где эти тонкости проявляются и зачем задавать это на собеседовании (знание языка ради знания языка это не ответ). Например вот эта %featurename% используется при оптимизации кода, а вот та влияет на качество архитектуры. По логике, если сюда пришел \"профи\", нечего ему тут смотреть он и так все знает. Всем остальным (мне в какой то степени) это покажется пособием на тему \"как зарезать человека на собесе каверзными вопросами\"\n\n","added":1547387145526,"answers":[{"id":"2ea4f2c0-a2cd-47b0-a616-76b545dda020","authorSrc":"GitHub","authorId":"Miha-x64","text":"На оптимизацию кода, конечно, влияет всё. Например, можно встретить в интернете такой Kotlin-код для Android:\n```\nval someView by lazy { findViewById(R.id.some_view) }\n```\nЕсли знаешь особенности компилятора — сразу понятно: на такую конструкцию сгенерировалось два «лишних» класса. Один — реализация `() -> View` для лямбды, второй — `KProperty` для property delegate. И вопросов «почему тормозит на старте» не возникает — более того, человек просто не пишет так с самого начала, т. к. понимает, что классы занимают место в APK, а на рантайме их нужно загрузить, верифицировать, слинковать и скомпилировать в машинный код.\n\nДругой пример. Java:\n```\naddListener(OnChangeListener) { ... }\nremoveListener(OnChangeListener) { ... }\n```\nKotlin:\n```\nval listener = { whatever -> ... }\n\nfun create() {\n javaObj.addListener(listener)\n}\n\nfun destroy() {\n javaObj.removeListener(listener)\n}\n```\nВ `create` `listener` (типа `(Something) -> Unit`) заворачивается в адаптер, чтобы соответствовать типу `OnChangeListener`. В `destroy` он заворачивается в такой же адаптер, только экземпляр другой, первому не равный, поэтому отписки не происходит.\n\nТретий пример: некоторые часто спрашивают, потокобезопасны ли object declarations. А можно просто посмотреть в байт-код — и сразу будет однозначный ответ: да, потокобезопасны, потому что создание экземпляра происходит в статическом инициализаторе, а ClassLoader обязан обеспечить потокобезопасность его выполнения.\n\n«Зарезать» ли кандидата — решает, как всегда, собеседующий. При большом желании он может сделать это и вопросом «сколько будет 2+2?» Я не предлагаю требовать/знать достоверно по каждому пункту, тем более — со звёздочкой. Главное — чтобы кандидат знал, как эти ответы найти (и проверить достоверность).","added":1548188972243,"answers":[{"id":"adae81c0-ea55-4d79-a2bb-3348737b6e43","authorSrc":"GitHub","authorId":"Miha-x64","text":"Про два лишних класса я не прав. Лишний класс генерируется один — для лямбды.\n`KProperty` же создаётся рефлекшеном.","added":1549984975616,"answers":[{"id":"b6479fc0-1d21-439e-8be4-6b8aee1c363b","authorSrc":"GitHub","authorId":"intmainreturn00","text":"\"И вопросов «почему тормозит на старте» не возникает\" - есть некоторые сомнения что лишний класс, или даже лишних 10 классов на старте в андроиде приведут к хоть сколько то ощутимой, измеримой задержке. кажется что топ 10 причин по которым приложение обычно проседает на старте даже близко не связаны с такими вещами как \"особенности компилятора\". можете привести какой то реальный пример что вам удалось это хоть как то измерить \\ пронаблюдать? ","added":1566235225537,"answers":[]}]},{"id":"a7daca71-b469-460f-94c0-3096b5e57959","authorSrc":"GitHub","authorId":"InsanusMokrassar","text":"> чтобы соответствовать типу OnChangeListener\n\nИмхо, явно указывать тип в любой непонятной ситуации, особенно с лямбдами, которые на самом деле не просто лямбды:)","added":1554272908203,"answers":[{"id":"7b8559d4-069a-449b-b7a2-2dc4a008d6d5","authorSrc":"GitHub","authorId":"InsanusMokrassar","text":"Я просто с таким даже не сталкивался как-то","added":1554272924850,"answers":[]}]}]}]},{"id":"70c50229-5489-4cbe-ad27-98cd286c75de","authorSrc":"GitHub","authorId":"InsanusMokrassar","text":"Это вопросы на какой-то уровень знания? Или, может, это как-то разграничивается? Просто тут свалены в кучу практически все (если не все) важные вопросы по котлину и не совсем понятно, что на какой уровень нужно понимать.","added":1554272769349,"answers":[{"id":"fbfea900-710c-469e-8cbd-5de8738a3688","authorSrc":"GitHub","authorId":"Miha-x64","text":"Любую фичу языка нужно понимать, чтобы использовать. Так что разбивать имеет смысл не на уровни, а на языковые конструкции.\nЗнаешь лямбды и функциональные референсы, функциональные типы, SAM и inline — отлично, можешь использовать.\nЗнаешь делегирование пропертей — понимаешь, почему лучше не использовать :)\nЯзык ведь относительно небольшой, после джавы осваивается легко. Не вижу никакой сложности в том, чтобы полностью прочитать документацию и заглянуть в байт-код разных языковых фич.","added":1557089754165,"answers":[]}]}]}