Почему в Dart 2.12 появился `abstract`?

Ответ

Ключевое слово abstract, официально представленное в Dart 2.12 вместе с null safety, не было "новым" в полном смысле. Оно стало обязательным для объявления абстрактных классов. Это изменение усилило выразительность системы типов и сделало дизайн кода более явным и безопасным.

Раньше (до Dart 2.12): Абстрактный класс можно было объявить просто добавив в него абстрактный метод. Это было неявно и могло вводить в заблуждение.

// Старый стиль (неявная абстрактность)
class Animal {
  void makeSound(); // Наличие абстрактного метода делало класс абстрактным
  void sleep() => print('Sleeping');
}
// var a = Animal(); // Runtime error: Cannot instantiate abstract class.

Теперь (Dart 2.12+): Модификатор abstract требуется явно. Это сразу сообщает и разработчику, и инструментам (анализатору, IDE), что класс является контрактом и не может быть инстанциирован.

// Новый стиль (явная абстрактность)
abstract class Animal {
  void makeSound(); // Абстрактный метод
  void sleep() => print('Sleeping'); // Реализованный метод
}

class Dog extends Animal {
  @override
  void makeSound() => print('Woof!');
}

// var a = Animal(); // ОШИБКА КОМПИЛЯЦИИ: Abstract classes can't be instantiated.
var d = Dog(); // OK

Практическая польза в Flutter:

  1. Чёткое разделение ответственности: Позволяет создавать чистые интерфейсы (контракты) для репозиториев, сервисов, use-cases, что является основой для тестируемой архитектуры (например, с Clean Architecture).
  2. Улучшенная поддержка инструментов: IDE может сразу показывать, какие классы нужно реализовать, а какие — нет.
  3. Безопасность: Ошибка попытки создания экземпляра абстрактного класса теперь ловится на этапе компиляции, а не во время выполнения. Это напрямую связано с философией null safety — перемещать ошибки из runtime в compile-time.

Ответ 18+ 🔞

А, ну это про ключевое слово abstract в Dart! Давай разберём, что за ерунда тут произошла, а то некоторые до сих пор не въезжают, в чём прикол.

Так вот, до версии 2.12, если ты хотел сделать абстрактный класс, можно было просто накидать в него абстрактных методов — и всё, класс автоматом считался абстрактным. Типа как негласная договорённость, понимаешь? Работало, но было неочевидно, особенно для новичков. Можно было случайно попробовать создать экземпляр и получить ошибку только в рантайме — а это, блядь, как обухом по голове, когда уже всё запущено и работает.

// Раньше было так — смотри, никакого `abstract`!
class Animal {
  void makeSound(); // Просто висит абстрактный метод
  void sleep() => print('Sleeping');
}
// var a = Animal(); // БАБАХ! Ошибка выполнения: нельзя инстанциировать абстрактный класс.

Ёпта, ну неудобно же! Подкрадывается ошибка, как хитрая жопа, в самый неподходящий момент.

А потом пришёл Dart 2.12 с null safety, и сказал: "Ребят, хватит это терпеть, давайте делать всё явно и по-взрослому". И ввели обязательное ключевое слово abstract. Теперь если класс абстрактный — ты это видишь сразу, с первого взгляда. И компилятор видит. И IDE не тупит. Красота!

// Теперь правильно — явно и понятно даже ребёнку
abstract class Animal { // ВОТ ОНО, слово `abstract` прямо в лоб!
  void makeSound(); // Абстрактный метод
  void sleep() => print('Sleeping'); // А можно и с реализацией, почему нет
}

class Dog extends Animal {
  @override
  void makeSound() => print('Woof!');
}

// var a = Animal(); // Сразу ошибка компиляции: абстрактные классы нельзя инстанциировать, ёпта!
var d = Dog(); // А вот это уже пожалуйста, работай

А на практике во Flutter это вообще огонь:

  1. Всё по полочкам: Хочешь описать контракт для репозитория или сервиса — нате вам abstract class. Чётко видно, что это интерфейс, а не готовая реализация. Архитектура сразу становится чище, тестировать проще — просто красота, ядрёна вошь!

  2. Инструменты не тупят: IDE теперь с первого взгляда понимает, что этот класс нужно наследовать и реализовывать, а не создавать. Подсказки стали адекватнее, автодополнение не предлагает ерунду.

  3. Безопасность, мать её! Самое главное — ошибка "создания абстрактного класса" теперь ловится на этапе компиляции. То есть ты ещё даже не запустил приложение, а тебе уже говорят: "Мужик, ты чего, это же абстрактный класс!". Это полностью в духе null safety — вылавливать проблемы как можно раньше, а не ждать, когда всё накроется медным тазом в продакшене.

Короче, изменение кажется мелким, но на деле — очень полезное. Заставляет писать более явный и понятный код. А в программировании, как и в жизни, чем меньше недоговорённостей — тем лучше.