среда, 23 марта 2016 г.

Про GOTO

Заметка для тех, кто знает, что такое оператор goto и особенно для тех, кто его переводит как "пошел на...".

Когда-то давно Эдгар Дейкстра (снимаю шляпу) написал статью про вредность goto. Авторитетный товарищ высказался об операторе goto в негативном ключе. Студенты же обычно еще с ветром в голове и любое радикальное замечание могут поднять на знамена, что собственно и произошло. И пошло - поехало. Присоединюсь к обсуждению, воспользовавшись свободой слова если не нарушать законы.

Все чаще со временем стал сталкиваться с правилами (внутрифирменными стандартами) кодирования, в которых было радикально черным цветом выведено: оператор goto запрещен. Сначала на это мало обращал внимание, думал что мало ли какая мысль в голове у человека произвелась, повзрослеет - одумается. Ан нет. Запрет на goto продолжает процветать. И меня это раздражает.

В чем, собственно, была суть статьи Дейкстры про goto? Он написал статью о том, что в его время (но это также применимо к любому времени), после набора молодых специалистов, может возникать проблема качества кода, и одна из сторон качества - читабельность другим сотрудником и модифицируемость кода другим сотрудником. Он указал, что по статистике на эту характеристику проекта влияет применение оператора goto. И что молодые специалисты, часто его употребляя, могут привести коды проекта в малопригодное состояние. В качестве одного из простых решений он принял решение отказаться от этого оператора.

Впоследствии (после его статистического анализа) было показано, что если в языке программирования присутствует некий набор общеалгоритмических конструкций, то оператор goto можно заменить на сочетание других операторов. Что собственно радикалы и подняли на знамена.

Впоследствии Дональд Кнут (снимаю шляпу дважды) также выпустил статью, показывающую, что есть конструкции управления выполнением программы, в которых замена оператора goto на посторонние конструкции вредна.

Мое личное мнение ближе к мнению Кнута и вообще никак не близко к мнению Дейкстры.

Оператор goto - это инструмент. Запрещать применение инструмента - это на мой взгляд нелепо, по меньшей мере. Проблемный? Может быть. Но на мой взгляд эта проблемность того же рода как проблемность со статистикой утечки памяти в программах работающих с указателями. "Если С++ работает с указателями и нам это непонятно, то мы им не будем пользоваться, тем более что в нем, говорят, утечки памяти тяжело обнаружить" - примерно такое мнение я уже не раз слышал. При этом глаза (к сожалению, только мои) сами собой делаются по пять копеек, ибо это глупость и нелепость. Если человек не умеет пользоваться инструментом - то надо просто научиться им пользоваться. Хорошая цитата из Алана Голуба: "Конструкторов спортивных велосипедов не волнуют проблемы детей, катающихся на трехколесных велосипедах".

Ситуация примерно как с ножом или молотком - это инструменты. Ими можно порезаться и попасть по пальцу. Лично я это неоднократно делал. Но почему-то ни разу в голову не пришло запрещать себе пользоваться ножом или молотком. При монтаже розеток меня не раз било током потому что забывал выключить рубильник на щитке или потому что на щитке отключалась не фаза а ноль, да так что оплавлялись пассатижи и отвертка и их приходилось выбрасывать или перетачивать. И что, никогда больше не монтировать розетки?

В практике не раз встречал ситуации, когда, выполняя ТЗ, переводишь задание на язык программирования и пишешь оператор goto. После того как функция выполнена, возникает интерес проверить, можно ли и как именно заменить этот оператор на другие, сохранив корректность выполнения. Переделываешь. И что получаешь?

Получаешь вместо одного оператора с комментарием "почему он тут" нагромождение операторов в самых разных строках, введение, инициализацию, проверки и прочее дополнительной или не одной переменной. Код "украшается". И для чего? Попробуй прокомментировать каждый оператор и что получишь? В каждом комментарии для этих нелепостей написать "этим стулом мастер Гамбс заменяет оператор goto"?

Вместо понятного и элегантного применения goto там, где ему место, получить нагромождение сверху и снизу тучи кода, который его заменяет? Получили улучшение читабельности и модифицируемости? Ответ очевиден.

Оператор goto прост и эффективен. Почему мне не использовать простое и эффективное решение с переходом там, где мне понадобился именно переход?

Приходилось писать машины состояний (исполнения байткода), в которых основа машины исполнения - это тотальный switch, сотни три-четыре альтернатив перехода и часть альтернатив заканчивается или прерывается банальным goto. Ухмыляясь в виртуальные усы, мечтаю сунуть такие задачки какому-нибудь стороннику Дейкстры, чтобы он предложил замену без goto. И если не сможет улучшить - всыпать плетей. Должен же человек отвечать за базар, в конце концов. И очень жаль, что не могу всыпать. Недоработочка.

Приходилось пользоваться даже не просто оператором goto, а вычисляемым оператором goto, когда место перехода вычисляется в зависимости от текущего состояния, и так что нагромождение if точно не спасает. Самым элегантным решением оказывалась ассемблерная вставка на пару строк с предварительной инициализацией таблицы меток. Ну нет в языке C++ вычисляемого goto, что ж поделать, изобразил на ассемблере. Но доходит до таких глупостей, что в некоторых новых языках программирования вообще отказываются даже от просто оператора goto.

В конце сформулирую свою позицию так. Каждому инструменту - свое место. И если где-то должен стоять оператор goto, то именно он там и должен стоять. А не его суррогаты. Работать, в конце концов, придется твоей программе, а не мнению твоего руководителя.

Комментариев нет:

Отправить комментарий