Что такое ошибка на миллион долларов (Million Dollar Mistake)?

Ответ

Это термин, введённый Тони Хоаром, для обозначения введения концепции null в языки программирования. В контексте Dart и Flutter это приводит к ошибкам времени выполнения, когда код пытается вызвать метод или обратиться к свойству у null-значения (например, NoSuchMethodError).

С введением null safety (Dart 2.12+) система типов помогает предотвратить эти ошибки на этапе компиляции. Переменные по умолчанию не могут быть null, если явно не помечены как nullable с помощью ?.

Пример и безопасная работа с nullable-типами:

String? nullableName; // Может быть String или null
String regularName = 'Flutter'; // Не может быть null

// Опасный вызов — может вызвать ошибку во время выполнения, если nullableName == null
// print(nullableName.length);

// Безопасные подходы:
// 1. Проверка на null (flow analysis)
if (nullableName != null) {
  print(nullableName.length); // В этой области видимости тип — String
}

// 2. Оператор безопасного вызова `?.`
print(nullableName?.length); // Выполнит length, если не null, иначе вернёт null

// 3. Оператор объединения `??` для предоставления значения по умолчанию
print(nullableName?.length ?? 0); // Если null, то использует 0

// 4. Оператор утверждения `!` (используйте с осторожностью, только если уверены)
print(nullableName!.length); // Говорит компилятору: "это не null". Выбросит ошибку, если окажется null.

Основная практика — максимально использовать не-nullable типы и явно обрабатывать nullable случаи через ?, ?? и условные проверки, чтобы ошибки на миллион долларов оставались в прошлом.

Ответ 18+ 🔞

А, ну это же классика, ёпта! Тот самый "ошибка на миллион долларов", который Тони Хоар сам назвал своим "миллиардным косяком". Представь: пишешь код, всё летает, а потом — бац! — какая-то переменная оказалась null, и твоё приложение накрывается медным тазом с криком NoSuchMethodError. Чистая рулетка, доверия ебать ноль.

Но потом в Dart 2.12 пришла null safety, и жизнь стала немного проще. Теперь система типов тебя страхует. По умолчанию, если ты не указал иначе, переменная null быть не может. Хочешь иметь возможность хранить в ней "ничего"? Тогда явно пометь вопросительным знаком — String?. И компилятор сразу начинает приставать: "Чувак, а ты уверен, что там что-то есть? А ну-ка подумай, э бошка!"

Вот смотри, как это работает на практике, чтобы не облажаться:

String? nullableName; // Может быть строкой, а может и пустотой, хуй с горы
String regularName = 'Flutter'; // Тут всегда будет текст, иначе компилятор взвоет

// Раньше бы тут написали и молились. Сейчас — нельзя, опасно!
// print(nullableName.length); // Пизда рулю, если nullableName == null

// Теперь безопасные способы, чтобы не бздеть:
// 1. Старая добрая проверка (компилятор умный, он поймёт)
if (nullableName != null) {
  print(nullableName.length); // Тут уже точно String, можно спать спокойно
}

// 2. Оператор безопасного вызова `?.` — сделает дело, если есть что, иначе вернёт null и не позорится
print(nullableName?.length);

// 3. Оператор `??` — для тех, кто любит подстраховаться. "Нет значения? Да похуй, вот тебе дефолтное!"
print(nullableName?.length ?? 0); // Если null, то печатаем ноль

// 4. Восклицательный знак `!` — это как крик "Я уверен, ёба!" Только если не уверен — будет тебе хиросима.
print(nullableName!.length); // Говоришь компилятору "заткнись и работай". Вылетит, если соврал.

Суть в чём: старайся по максимуму использовать обычные, не-nullable типы. А если уж приспичило с "пустотой" работать, обрабатывай её явно через эти операторы. Тогда эти ебаные ошибки на миллион долларов останутся в прошлом, как страшный сон.