IF ... ELSE ... END-IF
Как COBOL-программа выбирает, что делать дальше — и почему сравнивать строки здесь не так просто, как кажется.
IF — конструкция, которая проверяет условие и выполняет один из двух блоков кода в зависимости от результата, а END-IF — обязательная точка, где эта конструкция заканчивается.
Зачем в языке вообще нужен IF
Любая программа рано или поздно должна на что-то реагировать по-разному. Клиенту банка начислить проценты, если у него на счету больше определённой суммы, и не начислять, если денег меньше. Заказ пометить как «просроченный», если дата доставки прошла, и оставить в работе, если ещё нет. Без условной конструкции программа могла бы делать только одно и то же для всех данных подряд — а это бесполезно почти для любой реальной задачи.
В COBOL за это отвечает конструкция IF ... ELSE ... END-IF. Она появилась в языке ещё в конце 1950-х и с тех пор почти не менялась — те же банковские системы, которые писались на COBOL полвека назад, используют ровно этот же синтаксис сегодня.
Синтаксис и разбор по строкам
Вот минимальный пример: проверка, хватает ли денег на счету клиента для списания.
IF WS-BALANCE >= WS-WITHDRAW-AMOUNT
SUBTRACT WS-WITHDRAW-AMOUNT FROM WS-BALANCE
DISPLAY "Списание выполнено"
ELSE
DISPLAY "Недостаточно средств"
END-IF.Разберём построчно:
IF WS-BALANCE >= WS-WITHDRAW-AMOUNT— условие.WS-BALANCEиWS-WITHDRAW-AMOUNT— это переменные (в COBOL их принято называть «поля» или «элементы данных»), а>=значит «больше или равно», совсем как в математике.- Следующие две строки выполняются, только если условие верно — это ветка «истина».
ELSE— начало ветки «ложь». Она необязательна: можно написать IF без ELSE, и тогда при ложном условии программа просто ничего не сделает и пойдёт дальше.END-IF— явный конец конструкции. Это отдельная особенность COBOL: в большинстве современных языков границы IF задают фигурные скобки или отступы, а здесь нужно явное слово-терминатор.
Отступы в примере — это просто договорённость программистов для читаемости, сам компилятор на них не смотрит (в отличие, например, от Python). Но точка в самом конце обязательна — она завершает весь оператор целиком.
Почему END-IF обязателен
В очень старом COBOL (до стандарта 1985 года) специального END-IF не было вообще — границу условия обозначала точка в конце. Проблема в том, что если внутри IF несколько инструкций, точка ставилась только один раз, в самом конце всей конструкции — и было легко случайно поставить её раньше, оборвав условие на середине. Это одна из классических ошибок, из-за которых старый банковский код COBOL иногда вёл себя не так, как задумывалось: часть кода, которая должна была быть «внутри» IF, на самом деле выполнялась всегда.
Явный END-IF решает эту проблему — граница видна сразу, и её нельзя перепутать. В современном коде END-IF пишут почти всегда, даже когда без него можно было бы обойтись.
Сравнение чисел и строк — в чём разница
С числами всё интуитивно: >, <, =, >=, <= работают как в математике. Но COBOL исторически — язык обработки текстовых полей фиксированной длины (вспомните перфокарты и построчные файлы), и сравнение строк устроено иначе, чем в Python или JavaScript.
Допустим, есть два поля: WS-NAME-A длиной 10 символов со значением "IVAN" и WS-NAME-B длиной 10 символов со значением "IVAN ". На первый взгляд это разные строки — во втором случае явно есть лишний пробел. Но в COBOL оба поля физически хранят ровно 10 символов, и короткое значение "IVAN" автоматически дополняется пробелами справа до полной длины поля. Поэтому:
IF WS-NAME-A = WS-NAME-B
DISPLAY "Имена совпадают"
END-IF.Вывод:
Имена совпадаютСравнение вернёт «истина» — потому что оба поля после дополнения пробелами выглядят одинаково: "IVAN ". Это удобно, когда данные приходят из фиксированных файлов, но может удивить, если вы ждёте поведения как в языках, где строки сравниваются посимвольно без выравнивания. Ещё один нюанс: если сравнивать поля разной длины, более короткое тоже мысленно «дополняется» пробелами до длины более длинного перед сравнением — само поле в памяти при этом не меняется.
Мини-пример: классификация возраста
Более развёрнутый пример — определить возрастную категорию для анкеты.
IF WS-AGE < 18
MOVE "Несовершеннолетний" TO WS-CATEGORY
ELSE
IF WS-AGE < 65
MOVE "Взрослый" TO WS-CATEGORY
ELSE
MOVE "Пенсионный возраст" TO WS-CATEGORY
END-IF
END-IF.
DISPLAY "Категория: " WS-CATEGORY.Вывод (при WS-AGE = 40):
Категория: ВзрослыйЗдесь один IF вложен в ELSE-ветку другого — это стандартный способ проверить несколько вариантов подряд, аналог цепочки else if в других языках. Каждый вложенный IF требует своего END-IF, поэтому у конструкций с несколькими уровнями вложенности легко потерять счёт скобкам-терминаторам, если не следить за отступами.
Частые ошибки
- Забыть END-IF в многострочном блоке. Если внутри IF несколько операторов и нет END-IF, компилятор либо выдаст ошибку, либо (в старом стиле с точкой) свяжет границу условия не с той строкой, что задумывалось.
- Ждать «умного» сравнения строк, как в Python. Помните: COBOL сравнивает поля фиксированной длины с выравниванием пробелами, а не «содержимое» в привычном смысле — лишние пробелы в середине строки, а не в конце, всё равно будут учтены.
- Путать
=с присваиванием. В COBOL присваивание — это отдельный операторMOVE значение TO поле, а=внутри IF — только сравнение. Смешать их синтаксически нельзя, но концептуально этой разницы иногда не хватает тем, кто пришёл из языков, где=используется для обоих действий.
Итоги
- IF...ELSE...END-IF — основная условная конструкция COBOL, END-IF обязателен для явной границы блока.
- ELSE необязателен, если нужно действие только при истинном условии.
- Числа сравниваются как обычно, а строковые поля COBOL сравнивает с учётом дополнения пробелами до фиксированной длины поля.
- Вложенные IF внутри ELSE — стандартный способ проверить несколько условий по очереди.