Наука — Школе |
Говорить о структурном программировании, как о "программировании без GOTO" — слишком грубое упрощение. Если просто взять наивную программу с парой вложенных циклов и выходами из них с помощью GOTO и механически исключить GOTO, вводя дополнительные логические переменные, то "исправленная" программа может оказаться еще менее ясной, чем исходная.
Вот пример подобного рода программы без единого GOTO, наваянной на Компонентном Паскале энергичным (и, кстати, талантливым) программистом-самоучкой:
PROCEDURE (obj:setGuider) generate*,NEW;
VAR exit,reset:BOOLEAN;i:INTEGER;
BEGIN
exit:=FALSE;reset:=FALSE;i:=LEN(obj.content)-1;
WHILE exit=FALSE
DO
IF i>=0 THEN
obj.content[i].checkFull();
IF obj.content[i].full=FALSE THEN
obj.content[i].add();
exit:=TRUE;
ELSE
reset:=TRUE;
obj.content[i].reset();
DEC(i);
END;
IF (reset=TRUE) & (exit=TRUE) THEN
obj.setMax(i);
END;
ELSE
exit:=TRUE;
obj.end:=TRUE;
END;
END;
END generate;
Сколько времени потребуется читателю, чтобы понять смысл фигурирующего здесь цикла WHILE?
Отметим достаточно типичное неумение пользоваться логическими выражениями: WHILE exit = false DO ... вместо просто WHILE ~exit DO ...
А вот эквивалентная хорошо структурированная программа, полученная тождественными преобразованиями:
PROCEDURE ( sg: SetGuider ) Next*, NEW;
VAR i: INTEGER; c: POINTER TO ARRAY OF
Set;
BEGIN
c := sg.content;
i := LEN(c) - 1;
WHILE ( i >= 0 ) & c[i].IsFull() DO
c[i].Reset();
i := i - 1
END;
IF i < 0 THEN
sg.end := TRUE
ELSE
c[ i ].Inc();
IF i < LEN( c
) - 1 THEN sg.SetMax( i ) END
END
END Next;
Здесь сразу видно, что цикл WHILE устроен по принципу поиска в массиве первого с конца элемента, не обладающего свойством c[i].IsFull():
ПОКА (не вышли из массива) И (текущий элемент не удовлетворяет условию поиска) ДЕЛАТЬ ..,
а оператор IF в конце — стандартный обработчик двух возможных состояний после выхода из цикла:
ЕСЛИ (вышли из массива, т.е. дошли до конца, не найдя элемента) ТО ...
А теперь представьте себе, что вам нужно модифицировать эту
программу под новую задачу: очевидно, что во втором случае это сделать не только
намного легче, но и минимален риск внести при исправлении ошибку.
Именно в этом и заключается цель применения структурного программирования.
Впрочем, польза от механического исключения GOTO есть: по крайней мере, так можно доказать, что без GOTO можно обойтись в любых программах (см. книгу Лингера и др. в списке литературы).
Наука — Школе |