Pull to refresh

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) и размера класс-файлов. Для того, чтобы этого избежать, и нужен синтетический метод с битовой маской. С вызывающей стороны в битовой маске передаётся информация о том, для каких параметров аргументы переданы, а для каких должны быть использованы дефолтные. Синтетический метод проверяет битовую маску и на её основе вычисляет только нужные дефолтные значения, после чего передаёт всё вместе "настоящему методу".


То есть битовая маска нужна, чтобы не страдать от экспоненциального роста числа комбинаций отсутствующих аргументов.

Спорное решение. С одной стороны, конечно, можно изменить значение по умолчанию в библиотеке без перекомпиляции всего приложения, с другой стороны, разве приложение не опирается на значение по умолчанию, которое было в момент разработки? То есть фактически частично изменяется контракт метода и, быть может, было бы лучше сохранить исходное значение по умолчанию. Как нужно — 50/50 зависит от ситуации. Значит было бы логично выбрать более производительное решение.
Для вызывающего кода отсутствие аргумента для дефолтного параметра может также иметь семантику «я не хочу ничего решать, сделайте там сами что-нибудь разумное», в таком случае код не опирается на значения по умолчанию.

Более того, значения по умолчанию — это произвольные выражения, которые могут ссылаться на детали реализации библиотеки. «Осевшие» в вызывающем коде выражения дефолтных аргументов могли бы оказаться даже бинарно несоместимыми с новой версией библиотеки, поэтому их тоже можно считать деталями реализации.
Sign up to leave a comment.