[Перевод] if-then-else кто-то должен был изобрести
If-then-else — это условные конструкции в языках программирования: если (if) что-то истинно, тогда (then) выполнить одно действие, иначе (else) выполнить другое действие.
Это ведь просто английский? На самом деле нет.
В обычной речи на английском нельзя использовать «else» в качестве союза, это слово используется так только в компьютерных программах.
Откуда вообще взялось else
? Это загадка. Настолько микроскопическая деталь, что она не попала в книги по истории языков программирования.
Похоже, оно не появилось из отчётов, судопроизводства или алгоритмов, которые писались ещё до появления компьютеров. В этих текстах можно найти «if yes», «if no» и «if however», но не «else».
Похоже, что первым компьютером, способным выполнять различные команды в зависимости от предыдущих вычислений, был ЭНИАК. В 1946 году Хаскелл Карри и Уилла Уайатт написали отчёт с описанием программы, инвертирующей функцию. Для конструкции, принимающей решение на основании того, какое из двух чисел больше, они использовали название «discrimination» («выделение»).
У ЭНИАК не было команды под названием «discriminate». Она программировалась проводами и ручками на коммутационной панели, а панель управления команды, выполняющей вычисление для принятия решения, была подключена физическими проводами к командам, которые должны следовать за ней.
Вскоре у компьютеров появилось достаточно памяти, чтобы программы можно было хранить в ней, а не соединять проводами. Вместо физической последовательности команд возникла числовая. Несколько специальных команд могли приказать компьютеру перейти в другую точку последовательности.
Вот пример команды условного перехода одного из первых коммерчески изготавливавшихся компьютеров. Она проверяет, было ли отрицательным последнее вычисленное значение. Если да, то она перенаправляла поток управления в определённое место в памяти, в противном случае выполнялся переход к следующей команде.
Она предназначалась для определённого шаблона применения: если нужно было выполнить задачу, допустим, 10 раз, то программа считала, сколько раз она уже была выполнена, после чего вычитала 10. Если результат был отрицательным, значит, задача ещё не завершена, и выполнялся переход на ещё один повтор.
Эта идея была перенесена в первые языки программирования высокого уровня, например, в язык Хэлкомба Лэнинга и Нила Цирлера для компьютера Whirlwind. Его условный переход работал аналогичным образом, только количество циклов программы было алгебраическими вычислениями, а не одиночными машинными командами.
Первый распространённый язык программирования Фортран популяризировал идею указания переходов в три места одновременно в зависимости от результата вычисления: ноль, положительный или отрицательный. В Фортране эта конструкция получила название «if».
Тройственный «if» был более мощным, чем простая проверка на отрицательность, но и больше сбивал с толку, ведь каждое решение подразумевало разрыв в потоке управления, а раньше программистам достаточно было думать о обычном потоке, который продолжал выполнение программы, и необычном, который выполнял переход.
Язык Flow-Matic, разработанный Грейс Мюррей Хоппер до Кобола, немного упростил восприятие тройственного if: теперь сравнивались не знаки чисел, а два числа. В нём появилось название «otherwise» для случая, когда результат сравнения не равен тому, что мы ищем.
Каждый из этих языков программирования был связан с конкретным компьютером конкретного производителя. В 1958 году две американские и две немецкие компьютерные организации запустили совместный проект по разработке стандартного машинонезависимого языка, который было бы удобно обсуждать между людьми. На совместную конференцию каждая из групп привезла свой проект предложения.
Немецкие авторы сделали два больших концептуальных шага в формулировании конструкции «if».
Во-первых, в их проекте условный оператор управлялся любым булевым выражением, а не отдавал особый приоритет виду «меньше/равно/больше».
Вторым серьёзным шагом стало то, что вместо выполнения резкого перехода в потоке управления, их конструкция «if» вызывала только временное отклонение потока. В конце условной конструкции, вне зависимости от истинности или ложности условия, программа продолжала работу с конструкции «always», находящейся в конце блока. Единственное отличие заключалось в том, выполняются ли дополнительные конструкции.
В примере выше показаны два «if» в одном блоке; можно предположить, что второй должен работать, как современный «else if». Но на самом деле программа ожидает вычисления всех условий, даже если первое оказалось истинным. Поэтому если конструкции, управляемые первым if, изменяют значение, от которого зависит второе сравнение, то могут выполниться оба блока конструкций.
В предложении немцев было и что-то вроде «else», однако в совершенно ином, условном виде, под названием «case». В отличие от современного «case», их «case» был ещё одним способом записи булевых условий, при котором условия были выделены в отдельный блок от управляемых ими конструкций. Похоже, разработчикам казалось, что такой вид будет проще для более сложных сравнений.
И здесь появляется первый случай использования «else» для случая, в котором неприменим ни один из остальных случаев.
Почему они назвали его «else»? Никто не знает.
Мы знаем только то, что этот документ изначально был написан на немецком и в спешке переведён на английский. Я думаю, что тщательно подобранное немецкое слово было переведено как архаичное английское слово, и потом его никогда больше не исправляли. К сожалению, у нас нет исходного текста на немецком, чтобы сравнить.
Предложение американцев тоже содержало идею управления конструкциями при помощи булевых выражений. В нём даже не было слова «if». Если за выражением следовала стрелка, то выражение управляло конструкциями, которые шли за этой стрелкой.
В такой записи это неочевидно, но в отличие от «немецкого» блока if, в американском варианте если одно выражение в блоке было истинным, то оно проходило по упрощённой схеме и пропускало все последующие выражения, как это делает сейчас «else if».
Две организации провели совместное совещание и объединили свои предложения в один документ, который назвали International Algebraic Language. Вскоре этот язык переименовали в Algol (Алгол).
Конструкция «if» в обобщённом документе походила на немецкое предложение, однако в нём отсутствовала конструкция «always» в конце блока. Каждый «if» стоял отдельно, и если требовалось, чтобы одним выражением управлялось несколько конструкций, то можно было использовать «begin» и «end» для их группирования.
В такой формулировке «if» не было ничего похожего на «else».
Однако в Algol 58 была и вторая условная форма, называемая «if either». В этой форме можно было написать «or if» для выполнения той же задачи, которую мы сегодня выполняем при помощи «else if». Но ничего эквивалентного самого по себе «else» без другого «if» не было.
На следующий год история становится запутанной — на конференции было представлено несколько статей об Алголе. Одной из них была статья, в которой Джон Бакус, ранее руководивший проектом Фортрана, предложил идею формальных грамматик для языков программирования.
Описанный Бакусом Алгол не имел условной формы «if either». Вместо неё было ключевое слово «converge», заставлявшее «if» самого верхнего уровня внутри его блока вести себя как «else if». Непонятно, была ли эта идея для улучшения «if either», или более ранняя идея, от которой отказались в пользу «if either».
Как бы то ни было, «if either» вскоре был заменён. В 1957 году Джон Маккарти из MIT написал предложение проекта, который позже превратится в LISP — ещё один очень старый язык программирования, существующий и по сей день. В его предложении изложена идея условного выражения, заменяющая условную конструкцию.
Важное отличие заключается в том, что выражение всегда должно иметь значение, а конструкция просто может не выполняться, если контролирующее её условие ложно.
Итак, его «if function» всегда завершается оператором «otherwise», назначающим значение выражения, если ни одно из остальных условий не истинно.
Идея условных выражений Маккарти вдохновила Клауса Самельсона объединить в 1959 году две независимые условные модели Алгола. Он полностью избавился от формы «if either», оставив только «if», но добавил оператор под названием «else», который должен выполняться, если выражение, управляющее соответственным «if», оказывалось ложным.
При помощи «else if» можно было создавать цепочки условий, как и предыдущий «if either» позволял это делать при помощи «or if», но можно было и использовать «else» отдельно в последнем множестве конструкций, которое выполнялось, если ни одно из условий не оказывалось истинным.
«If-then-else» стала единственной условной формой, появившейся в отчёте об Алголе 60 на следующий год, и эту форму повторяли почти все последующие языки программирования.
Хотя сегодня для нас она кажется понятной, людям в 1960 году было сложно её воспринимать, поэтому в отчёте уделено полторы страницы объяснению её работы, в том числе и на этой стрелочной диаграмме.
Как я и говорил, использование «else» в качестве союза кажется странным. Язык программирования CPL Кристофера Стрейчи был прадедушкой языка C, а значит, и предком большинства современных языков программирования. Стрейчи отказывался использовать «else», называя его «невежественно ошибочным английским». Он считал, что следует писать «test… then… or», но это звучало тоже не очень естественно, и популярности не получило.
Язык программирования MAD тоже пошёл своим путём. Он известен своими чрезвычайно длинными словами, и в дополнение к использованию «whenever» вместо «if» он использовал «otherwise» вместо «else» и «or whenever» вместо «else if».
Также стоит упомянуть структурирование в примере из руководства по MAD. Прошли годы, прежде чем другие языки программирования переняли такой стиль форматирования, хотя сегодня мы и не можем представить себе чего-то другого.
Однако несмотря на то, что CPL и MAD отвергали слово «else», они сохранили форму и изменили только название. Проектировщики языков по-прежнему ищут идеальный способ написания цикла
for
, однако поиск совершенной условной формы, похоже, завершился в 1959 году. Спасибо Клаусу Самельсону, давшему нам инструмент для мышления и слово, над которым можно поломать голову.