C большим удовольствием прочитал статью С. Короткого “Работа над ошибками” (см. выше). Позволю себе сделать несколько примечаний.

 

Когда я писал о причинах появления ошибок в программах, то прежде всего имел в виду логические ошибки, которые не имеют никакого отношения к невнимательности программиста, а связаны исключительно с физической невозможностью держать в голове все нюансы функционирования программы. Это касается прежде всего крупных проектов в миллионы строк, создаваемых группами программистов. К сожалению, с увеличением размера проекта его сложность возрастает не линейно, а экспоненциально. При этом обычно “вылазят” ошибки, вызванные побочными эффектами, не предусмотренными на стадии проектирования.

 

Но наибольшую трудность вызывают задачи, требующие моделирования действий человека-эксперта. Как известно, труднее всего поддается кодированию то, что для нас с вами тривиально. В таких ситуациях приходится реализовывать очень сложные логические операции с учетом множества взаимосвязанных ограничений. Программирование подобных операций занимает сотни тысяч строчек кода и обычно не поддается полноценному тестированию. К сожалению, разбивка кода на небольшие кусочки текста приводит к появлению десятков тысяч небольших процедур, в которых запутаться можно еще быстрее, а композиция их отнюдь не упрощает структуру программы. По сути, возникает свой “язык программирования” с операторами-процедурами, выполняющими некие операции над абстрактными внутрипрограммными типами данных. Эти тысячи процедур все равно придется использовать как макрооператоры в операциях выбора, при этом логическая структура сложного кода фактически не меняется.

 

Не помогает также и объектный подход, который оправдывает себя на этапе проектирования системы. Если же требуется осуществить, допустим, глобальную оптимизацию некоей иерархической структуры множества разнотипных объектов, то, так или иначе, придется писать отдельный модуль, осуществляющий эту оптимизацию путем сложных логических манипуляций. Если число условных веточек в подобной задаче достигает нескольких сотен, то можно с уверенностью сказать, что ошибки в ней уже ждут своего часа. Ведь уровень вложенности в три-четыре оператора if практически лишает текст понимаемости, даже если он занимает 10 строк.

 

Выход вообще-то известен достаточно давно, еще с периода расцвета идей структурного программирования. Он заключается в разбиении таких задач на ряд последовательных подзадач, каждая из которых осуществляет определенное модифицирующее воздействие на программные структуры данных (своего рода моделирование на уровне логических автоматов). Принцип последовательности здесь главный. Лучше даже пожертвовать эффективностью, но добиться упрощения структуры программы. Операторы if, вложенные друг в друга, при таком подходе исключаются полностью, причем их удаление отнюдь не приведет к усложнению в “оставшихся” операторах. Я, конечно, имел в виду не совершенствование ранее написанного текста, а этап программирования с нуля, когда последовательная структура кода продумана настолько хорошо, что необходимость использования вложенных if отпадает. Можно, кстати, строго доказать, что любой алгоритм можно представить в виде последовательности действий при отсутствии вложенных if.

 

Что касается самого goto,  -  один из отечественных разработчиков оригинального Си-компилятора рассказывал, что ему удавалось проводить глобальную оптимизацию кода, если в исходном тексте не было операторов перехода. Возможно, это одна из причин, по которой этот оператор был исключен из Java. С другой стороны, нельзя не учитывать мнение зарубежных разработчиков известных программных продуктов. Они в сетевых конференциях заявляют, что в ряде задач нет более удачного средства повышения эффективности, чем goto! На самом деле  -  он транслируется в одну команду, выполняется очень быстро и позволяет избежать лишних проверок в коде, получающемся при автоматической трансляции циклов типа for. Иными словами, можно писать на Си, как на Ассемблере, для управления последовательностью вычислений используя только оператор if со следующим за ним оператором перехода. Выигрыш в некоторых задачах, например при работе с трехмерной графикой, получается очень существенным.

 

По поводу расширенного case см. статью В. Очкова в седьмом номере “КомпьютерПресс” за этот год. В ней приводится пример простой задачи, занимающей 15 строк, которая с помощью вложенных if реализуется крайне ненаглядно и которую сделать “прозрачной” для понимания без goto или расширенного case невозможно. Читатели PC Week/RE сообщили, что этот оператор имеется в языке REXX, во внутреннем языке FoxPro, в Paradox (ObjectPal) и, следовательно, был востребован достаточно давно.

 

Сергей Бобровский

 

К Сергею Бобровскому можно обратиться по адресу: sergei95@glas.apc.org.

Версия для печати