Generic-конструкторы в Dart: черновик спецификации

Я — MADTeacher, автор книг по Dart/Flutter/ИИ в программировании и преподаватель. На канале разбираю свежие фичи языка и фреймворка, объясняю, как и когда их применять, и показываю всё на живых примерах кода. Меньше воды — больше практики: от конструкторов и метапрограммирования до производительности, интеропа и тестирования, а также поднимаю тему использования ИИ для разработки программных продуктов. Если хотите понимать Dart и Flutter в эпоху ИИ глубже — вы по адресу.

dartgeneric-конструкторыконструкторы

Замечен черновик новой фичи - Generic Constructors 😩

Не прошло и пары месяцев с упоминания о предыдущем заходе на поле конструкторов с фичей Enhanced Constructors, как команда Dart, в тайне от сообщества, начала работу над черновиком еще одного конструктора... на этот раз - универсального... 🛑

По задумке разработчиков, Generic-конструкторы должны позволить объявлять конструкторы с собственными параметрами типов, которые не отражаются напрямую в типе возвращаемого объекта. Это значит, что можно задавать дополнительные зависимости между аргументами конструктора. Сейчас приходится приходится прибегать к менее безопасным способам.

Планируется 2 типа Generic-конструкторов 🫠

1️⃣Простой

На данный момент, если требуется задать связь между параметрами конструктора (например, значение и функция для его вычисления), приходится использовать универсальные типы вроде Object? и Function, что снижает статическую проверку типов:

class C {
  final int i;
  C(this.i);
  C.computed(Object? x, Function func): this(func(x)); // Unsafe!
} 

с появлением этого конструктора можно будет явно указать зависимость между параметрами, исключая необходимость runtime-проверок

class C {
  final int i;
  C(this.i);
  C.computed<X>(X x, int Function(X) func) : this(func(x));
}

void main() {
  C(42); // Обычный конструктор.
  C.computed('Hello', (s) => s.length); // Автоматическое выведение типа.
  C.computed<String>('Hello', (s) => s.length); // Явное указание типа.
}

2️⃣ Условный

С помощью этого типа Generic-конструктора можно будет объявлять конструкторы, которые корректно работают только при определенных типовых аргументах.

Сейчас приходится писать такой код

class D<X> {
  final X x;
  final int Function(X, X) _compare;
  D(this.x, this._compare);
  D.ofComparable(X x): // Unsafe!
      this(x, (dynamic x1, dynamic x2) => x1.compareTo(x2)) {
    // Check at run-time that `X extends Comparable<X>`.
    if (<X>[] is! List<Comparable<X>>) {
      throw ArgumentError("The type argument failed"
          " to satisfy `X extends Comparable<X>`.");
    }
  }
}

использование универсального конструктора сделает его более лаконичным:

class D<X> {
  final X x;
  final int Function(X, X) _compare;
  D(this.x, this._compare);
  D<X>.ofComparable<X extends Comparable<X>>(X x)
      : this(x, (x1, x2) => x1.compareTo(x2));
}

void main() {
  D.ofComparable(1); // OK, num удовлетворяет Comparable.
  D.ofComparable<num>(1); // Тоже OK.
  D.ofComparable(C(42), (c1, c2) => c1.i.compareTo(c2.i)); // OK.
  D.ofComparable(C(42)); // Ошибка компиляции – тип не соответствует.
}

p.s. Вот теперь я уже точно уверен, что в команде Dart нашелся какой-то маньяк конструкторов... иначе как объяснить такой набор: по-умолчанию, фабричный, именованный, константный, а теперь вот еще первичный, объявляющий, расширенный и универсальный?👀

👍 - больше конструкторов Богу конструкторов
👌 - сомнительно, но Окей
👎 - не вижу от него пользы

#dart_lang@madteacher_channel

Дискуссия

Eugene Voyner
dart идёт в энтерпрайз семимильными шагами?
Иван Каршакевич
Eugene Voyner
dart идёт в энтерпрайз семимильными шагами?
Ну точно быстрее KMP)
Присоединиться к обсуждению →

Читайте так же