Пирамида судьбы

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску

В программировании проблема под названием пирамида судьбы — это довольно распространённый случай, который возникает при структурировании программы путём вложения друг в друга множества однотипных конструкций для обеспечения корректности вычислений. Возникает довольно часто при проверке нулевых указателей или при обработке обратных вызовов.[1] Два примера, имеющих отношение к данному термину, связанные с определённым стилем программирования в JavaScript[2], а также вложенные друг в друга операторы if в ООП языках когда один из объектов может иметь нулевой указатель.[3][4]

Примеры[править | править код]

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

theWidth = windows("Main").views(5).size().width();

Данный код содержит четыре отдельные команды. Сначала в коллекции окон находится окно с именем «Main», затем среди изображений внутри данного окна выбирается изображение номер 5, далее вызывается метод size, возвращающий структуру содержащую размеры данного изображения, и в заключение вызывается метод width для данной структуры, производящий результат, который помещается в переменную theWidth.

Проблема здесь состоит в том, что код отталкивается от факта существования каждого из перечисленных значений. Несмотря на то, что вполне резонно ожидать наличия размеров у каждого изображения, а также ширины у каждого размера, мы никогда не можем гарантировать ни существование окна с именем «Main», ни того что у него будет пять изображений. Если одно из вышеперечисленных обстоятельств не будет иметь места, один из методов будет применён к нулевому указателю, что приведёт к ошибке.

Чтобы избежать ошибки, программист вынужден проверять существование объекта перед каждым следующим вызовом. Безопасная версия кода может выглядеть так:

if windows.contains("Main") {
    if windows("Main").views.contains(5) {
        theWidth = windows("Main").views(5).size().width();
        //далее код, использующий theWidth
    }
}

Если программист желает использовать это значение различным образом, в зависимости от того существует ли оно или нет, то в таком случае весь полезный код внутри конструкции if будет существенно смещён вправо, что приводит к трудностям при чтении кода. Это вынуждает применять «плоские» конструкции, например:

if windows.contains("Main") { theWindow = windows("Main") }
if theWindow != null && theWindow.views.contains(5) { theView = theWindow.views(5) }
if theView != null {
    theWidth = theView.size().width();
    //дальнейший код
}

или:

if !windows.contains("Main") {
    // обработчик ошибки
} else if !windows("Main").views.contains(5) {
    // обработчик ошибки
} else {
    theWidth = windows("Main").views(5).size().width();
    //далее код, использующий theWidth
}

Конструкции подобного рода весьма распространены и некоторые языки программирования в настоящее время предлагают некоторое подобие синтаксического сахара для борьбы с данным явлением. Например, в Apple Swift реализована концепция оператора безопасной навигации в операции if[5]. В тоже время в Microsoft C# 6.0 и Visual Basic 14 добавлены элвис-операторы ?. и ?[ для доступа к членам класса и индексирования, соответственно.[6][7][8] Основная идея — позволить цепочке вызовов методов возвратить null немедленно, как только встретится отсутствующий объект, например код:

theWidth = windows("Main")?.views(5)?.size.width;

должен присвоить null переменной theWidth если либо «Main», либо пятое изображение отсутствуют, либо завершить вычисление и вернуть ширину в том случае если они оба существуют. Во многих ситуациях программист должен выполнять различные действия в двух вышеперечисленных случаях, поэтому Swift предлагает дополнительный синтаксический сахар для данных обстоятельств: выражение if let, известное также под именем «необязательная привязка»:

if let theView = windows("Main")?.views(5) {
    //код если view существует...
    theWidth = theView.size.width
}

Ссылки[править | править код]

  1. Dave Herman. Why coroutines won't work on the web. The Little Calculist (14 декабря 2011). Архивировано 6 марта 2016 года.
  2. The Pyramid of Doom: A javaScript Style Trap (27 ноября 2012). Архивировано 9 декабря 2015 года.
  3. Eberhardt, Colin Tearing Down Swift's Optional Pyramid Of Doom (8 декабря 2014). Архивировано 31 июля 2016 года.
  4. New Language Features in Visual Basic 14 (9 декабря 2014). Архивировано 25 декабря 2014 года.
  5. Optional Chaining. Apple. Дата обращения: 6 ноября 2021. Архивировано 25 марта 2016 года.
  6. Null-conditional Operators (C# and Visual Basic). Microsoft. Дата обращения: 6 ноября 2021. Архивировано 23 июня 2016 года.
  7. What's New for Visual C#. Microsoft. Дата обращения: 6 ноября 2021. Архивировано 3 апреля 2017 года.
  8. What's New for Visual Basic. Microsoft. Дата обращения: 6 ноября 2021. Архивировано 17 ноября 2016 года.