Comments 7
Не понял, почему подстановка значений аргументов по умолчанию происходит не на этапе компиляции, а в рантайме с помощью каких-то битовых масок и т. д.
Это синтаксический сахар: вы, как разработчик, считаете, что это один метод API, а в реальности под капотом в байт-коде генерируется каждая вариация метода с отсутствующими параметрами. И еще в каждом из этих методов происходит проверка побитово, пришел ли этот параметр.
fun foo(bar: Int, baz: Int = 10) { }
void foo(int bar, int baz) {}
void foo(int bar) { foo(bar, 5); }
Не ясно для чего делать проверки побитово
под капотом в байт-коде генерируется каждая вариация метода с отсутствующими параметрами
На самом деле в этом месте в статье неточность, по умолчанию в байт-коде вообще не генерируются перегрузки без отдельных аргументов, а есть только два метода: один с настоящей сигнатурой функции (такой, как же, как в коде) и ещё один синтетический с добавленной битовой маской. Для вызовов из Котлина этого всегда хватает.
Если перегрузки без аргументов Вам всё-таки нужны (для Java-интеропа), то включить генерацию дополнительных методов можно с помощью аннотации @JvmOverloads
. Но! Даже с ней перегрузок методов будет сгенерировано не 2^n (где n — число параметров со значениями по умолчанию), а всего n — это будут методы с отброшенными с конца параметрами.
В идиоматичном коде на Котлине часто встречаются и функции с большим числом дефолтных параметров. При сколько-нибудь существенном числе дефолтных параметров (даже уже на четырёх) генерировать 2^n перегрузок было бы очень накладно в смысле числа методов (актуально для Android) и размера класс-файлов. Для того, чтобы этого избежать, и нужен синтетический метод с битовой маской. С вызывающей стороны в битовой маске передаётся информация о том, для каких параметров аргументы переданы, а для каких должны быть использованы дефолтные. Синтетический метод проверяет битовую маску и на её основе вычисляет только нужные дефолтные значения, после чего передаёт всё вместе "настоящему методу".
То есть битовая маска нужна, чтобы не страдать от экспоненциального роста числа комбинаций отсутствующих аргументов.
Более того, значения по умолчанию — это произвольные выражения, которые могут ссылаться на детали реализации библиотеки. «Осевшие» в вызывающем коде выражения дефолтных аргументов могли бы оказаться даже бинарно несоместимыми с новой версией библиотеки, поэтому их тоже можно считать деталями реализации.
Kotlin performance on Android