Добавить объявление

Почему primary constructors в Dart сложнее, чем кажется

В Dart 3.13 появилась фича, которую ждали годами - primary constructors. Теперь класс с полями и конструктором можно объявить в одну строку. Но путь к этому решению был долгим. Команда Dart потратила много времени на обсуждение деталей и принятие компромиссов. Боб Нюстром написал большой разбор о том, через что пришлось пройти. Давайте разберем самые важные моменты из данного разбора.

Почему синтаксический сахар важен:


Primary constructors не добавляют в язык новых возможностей. Все, что можно сделать через них, уже можно было написать старым способом. Это чистый синтаксический сахар.

Вопрос в том, зачем он нужен. Синтаксический сахар оправдан в нескольких случаях.

  • Первый - когда новый способ просто лучше старого. Например, в Dart 2.0 сделали необязательным ключевое слово new при создании объектов. Старый синтаксис остался для совместимости, но никто его не использует.

  • Второй - когда синтаксис сильно упрощает частый сценарий. В Dart изначально не было enum. Их эмулировали через классы с константами. Когда добавили настоящие enum, код стал не только короче, но и понятнее.

  • Третий - когда синтаксис делает намерение более явным. Код в классах с константами не давал понять, что это enum. А настоящий enum сразу говорит о определенном наборе возможных значений.

Зачем нужен primary constructors:


Primary constructors решают конкретную проблему: объявление класса с конструктором, который просто сохраняет параметры в поля.

Без primary constructors код выглядит так:

class Point {
final int x;
final int y;
Point(int x, int y) : x = x, y = y;
}

С использованием initializing formals:

class Point {
final int x;
final int y;
Point(this.x, this.y);
}

Но разработчики хотели еще короче. Чтобы можно было просто написать так:

class Point(final int x, final int y);

Основная проблема:


Главная сложность: синтаксический клиф. Это когда ты начинаешь с простого синтаксиса, а потом хочешь добавить маленькое изменение, но оно не вписывается, и ты вынужден переписывать все.

Например, у класса есть primary constructor с кучей параметров. Потом нужно добавить логирование в конструктор. Если primary constructor не поддерживает тело, придется переписать все обратно на старый синтаксис.

Чтобы избежать этого, в Dart добавили блоки this { ... } внутри класса. Они позволяют добавить тело или инициализатор для primary constructor без переписывания всего.

class FormatterOptions(
final int indent = 0,
final int pageWidth = 80,
) {
this {
log.write('Created options.');
}
}

Новый синтаксис конструкторов:


Еще одно изменение касается объявления конструкторов. Раньше нужно было повторять имя класса:

class LongClassName {
LongClassName(); // безымянный
LongClassName.create(); // именованный
}

Теперь можно использовать ключевое слово new:

class LongClassName {
new(); // безымянный
new create(); // именованный
}

Для фабричных конструкторов:

class AnotherLongClass {
factory () { ... } // фабричный
factory create() { ... } // именованный фабричный
}

Это короче, особенно для длинных имен классов. И решает проблему с typedef и расширениями, где имя класса не всегда доступно.

Важно помнить:


Объявляющие параметры (final int x в primary constructor) работают только в primary constructor. Их нельзя использовать внутри тела класса. Решение было осознанным: чтобы не усложнять анализ кода и не делать поиск состояния класса труднее.

Есть и необычное сочетание: const new. На первый взгляд это выглядит противоречиво, потому что раньше new и const были взаимоисключающими при создании объектов. Но теперь new в объявлении конструктора означает лишь «это конструктор», а const - «этот конструктор должен быть константным». Если смотреть на это так, сочетание перестает быть странным.

Вывод:


Primary constructors в Dart 3.13 - это не просто очередной синтаксический сахар. Это результат долгого размышления о том, как сделать язык удобнее и проще.

Команда языка учла опыт других языков, добавила защиту от синтаксических клифов и изменила объявление конструкторов на более простое. В итоге код стал короче, , а язык чуть более приятным для повседневной работы.

Это не последнее изменение. Язык продолжает развиваться. Но primary constructors - хороший пример того, как дизайн языка может быть одновременно эволюционным и продуманным.
01.09.2026 83 632