Русская Википедия:Пирамида судьбы

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

В программировании проблема под названием пирамида судьбы — это довольно распространённый случай, который возникает при структурировании программы путём вложения друг в друга множества однотипных конструкций для обеспечения корректности вычислений. Возникает довольно часто при проверке нулевых указателей или при обработке обратных вызовов.[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
}

Ссылки

Шаблон:Примечания Шаблон:Изолированная статья