В 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 и расширениями, где имя класса не всегда доступно.
🔗 Читать подробнее
💡 Вывод:
Primary constructors в Dart 3.13 - это не просто очередной синтаксический сахар. Это результат долгого размышления о том, как сделать язык удобнее и проще.
Команда языка учла опыт других языков, добавила защиту от синтаксических клифов и изменила объявление конструкторов на более простое. В итоге код стал короче, , а язык чуть более приятным для повседневной работы.
Это не последнее изменение. Язык продолжает развиваться. Но primary constructors - хороший пример того, как дизайн языка может быть одновременно эволюционным и продуманным.
Подписаться на канал:
➡️ Flutter & Dart | Мобильный трудоголик
