Новая фича в Dart: Metaobjects

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

Dartmetaobjectsgenerics

Вот и настал момент, когда в спецификацию Dart, после нескольких переработок черновика, добавили фичу Metaobjects, а значит - по ней появилось куда более подробное описание ^_^

Какую проблему решает?

Сейчас мы можем вызывать статический метод или именованный конструктор (например, A.foo()) только через конкретный класс — A. Такое поведение ограничивает нас в работе с дженериками, запрещая в обобщенном коде инстанцировать объекты через их конструкторы или обращаться к их статическим методам (например, Х.foo()).

И это звиздец как бесит 🤬 (по крайней мере меня), т.к. нельзя удобно писать универсальный код, который работает с разными типами, у которых есть похожие статические методы.

Если эта фича пройдет все остальные стадии и будет утверждена, то в Dart появится возможность вызывать статические методы и конструкторы через переменные типа, а не только через точные имена классов:

 // Абстрактный интерфейс для печати
abstract class PrettyPrintable<X> {
  String prettyPrint(X x);
}

class A static implements PrettyPrintable<A> {
  final String name;
  A(this.name);
  static String prettyPrint(A a) => a.name;
}

class B static implements PrettyPrintable<B> {
  final int size;
  B(this.size);
  static String prettyPrint(B b) => "B of size ${b.size}";
}

// Функция, которая работает с любым типом, поддерживающим PrettyPrintable
String doPrettyprint<X static extends PrettyPrintable<X>>(X x) {
  return X.prettyPrint(x);
}

void main() {
  print(doPrettyprint(A("MyA")));
  print(doPrettyprint(B(42)));
}

Из представленного примера видно, как типы A и B используют prettyPrint, но без привязки к конкретному классу на этапе компиляции, что и позволяет писать более универсальный и гибкий код.

Что изменится с релизом фичи?

  1. Появится позднее связывание статических методов и конструкторов. То есть мы сможем вызывать статические методы или создавать экземпляры классов без жесткой привязки к типу на этапе компиляции. Например, вызов X.prettyPrint(x) работает так, как если бы X был классом, а не просто переменной типа.
  2. Добавится возможность объявлять интерфейсы для метаобъектов. Мы сможем объявлять интерфейсы, которые будут реализованы метаобъектами для различных классов, расширяя их возможности и при этом не меняя сам класс. Это увеличит гибкость кода и уменьшит его дублирование.
  3. Metaobjects дадут доступ к параметрам типа, что позволит писать код, который работает с типами даже в момент их выполнения. Если перефразировать на русский – в коде сына маминой подруги теперь будет дофигище сложных дженериков с заделом на "динамические" структуры данных.
  4. Изменения в синтаксисе и статическая гарантия типов. Новая пара ключевых конструкций static implements и static extends позволит компилятору гарантировать, что метаобъект будет иметь необходимый интерфейс для вызова соответствующих статических членов или конструкторов.
  5. Появятся имплицитно генерируемые классы. Для каждого класса, где при его объявлении используются static implements или static extends компилятор автоматически сгенерирует скрытый метаобъект-класс, который переадресует вызовы к статическим методам или конструкторам исходного класса. Передаю пламенный привет виртуальной таблице в C++ 🫠

Уже видите профит от этой Metaobjects?

  • 👍 – О, да, детка!!!
  • 👌 – Сомнительно, но Окей
  • 👎 – Отстой! (Не превращайте Dart в C++)
Миниатюра поста: крупный текст «Что же Dart такого нам готовит?» на тёмном фоне и круглая фотография автора Станислава Чернышева; иллюстрация к обзору Metaobjects.
Обложка поста с заголовком и фото автора

Дискуссия

TheLastRay (:
Ну чёт сомнительно Оно же специально отделено, чтобы не было путаницы между статическими методами, независящими от конкретного инстанса класса, и обычными Как сохранить это разделение в таком случае
Andrei Z
Который раз сталкиваюсь с тем, что примеры на print-ах очень плохо ложатся в голову 😳
MADTeacher | Станислав Чернышев
TheLastRay (:
Как сохранить это разделение в таком случае
не использовать static implements или static extends
Присоединиться к обсуждению →

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