Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Хорошие идеи взгляд из Зазеркалья.doc
Скачиваний:
7
Добавлен:
04.11.2018
Размер:
151.55 Кб
Скачать
        1. Особенности языков программирования

Языки программирования обеспечивают плодородную почву для спорных идей. Про некоторые из них с самого начала было ясно, что они не только сомнительны, но и просто являются плохими. Отличный пример представляют средства, предложенные в 1960 г. для языка Algol и позже для его преемников [1].

Большая часть людей считает, что язык программирования - это всего лишь код, единственное назначение которого состоит в конструировании программного обеспечения, выполняемого на компьютерах. Однако язык программирования - это модель вычислений, а программы - это формальные тексты, к которым применимы математические рассуждения. Модель должна определяться таким образом, чтобы ее семантика описывалась без отсылок на какой-либо нижележащий механизм, физический или абстрактный.

Поэтому явно плохой идеей является объяснение сложного набора особенностей и возможностей языка в толстых томах руководства. В действительности язык характеризуется не столько тем, что дает нам возможность программировать, сколько тем, что удерживает нас от использования недопустимых конструкций. Как заметил Дийкстра, наиболее трудной, ежедневной задачей программиста является недопущение беспорядка. Первичная и наиболее благородная обязанность языка состоит в том, чтобы помогать программистам в этой нескончаемой борьбе.

          1. Нотация и синтаксис

Стало модным относиться к нотации как ко вторичному аспекту, целиком зависящему от личных вкусов. Это отчасти верно, хотя выбор нотации не должен быть случайным. У этого выбора имеются последствия, обнаруживаемые в общем облике языка.

Общеизвестным плохим примером является выбор знака равенства для обозначения присваивания, восходящий к языку Fortran в 1957 г. и слепо повторяемый до сих пор массой разработчиков языков. Эта плохая идея низвергает вековую традицию использования знака "=" для обозначения сравнения на равенство, предиката, принимающего значения true или false. Но в Fortran этот символ стал обозначать присваивание, принуждение к равенству. В этом случае операнды находятся в неравном положении: левый операнд, переменная, должен быть сделан равным правому операнду, выражению. Поэтому x = y не означает то же самое, что y = x. В языке Algol эта ошибка была исправлена путем простого решения: присваивание обозначили через ":=".

Программистам, привыкшим к использованию знака равенства для обозначения присваивания, это может показаться придиркой. Но смешивание присваивания и сравнения действительно является плохой идеей, поскольку в этом случае требуется другой символ для того, что традиционно выражает знак равенства. Сравнение на равенство стали обозначать двумя символами "==" (впервые в языке C). Это является отвратительным последствием, приведшим к аналогичным плохим идеям использования "++", "--", "&&" и т.д.

В языках C, C++, Java и C# некоторые из этих операций вызывают побочные эффекты, известный источник ошибок программирования. Например, можно было бы принять "++" для обозначения увеличения значения на единицу, если бы то же самое не обозначало само увеличенное значение, что позволяет писать выражения с побочными эффектами. Неприятность состоит в удалении фундаментального различия между оператором и выражением. Оператор - это инструкция, подлежащая выполнению, выражение - это значение, которое надлежит вычислить.

Уродство конструкции обычно проявляется в комбинации с другими средствами языка. На языке C программист может написать конструкцию x+++++y, загадку, а не выражение, представляющую проблему даже для сложного синтаксического анализатора. Равняется ли значение этого "выражения" значению ++x+++y+1? Верны ли следующие соотношения?

x+++++y+1==++x+++y

x+++y++==x+++++y+1

Так можно было бы постулировать новую алгебру. Я нахожу совершенно удивительной невозмутимость, с которой мировое сообщество программистов приняло этого нотационного монстра. В 1962 г. установившиеся традиции аналогичным образом подорвало постулирование правой ассоциативности операций в языке APL. Тогда x+y+z неожиданно стало обозначать x+(y+z), а x-y-z - x-y+z.

У условного оператора языка Algol, представляющего пример неудачного синтаксиса, а не только плохого выбора символов, имелось две формы (S0 и S1 обозначают некоторые операторы):

if b then S0

if b then S0 else S1

Это определение порождает очевидную двусмысленность, получившую название проблемы "висящего else". Например, оператор

if b0 then if b1 then S0 else S1

можно интерпретировать двумя способами, а именно,

if b0 then (if b1 then S0 else S1) и

if b0 then (if b1 then S0) else S1,

возможно, приводящими к совершенно разным результатам. Следующий пример еще более серьезен:

if b0 then for i := 1 step 1 until 100 do if b1 then S0

else S1,

поскольку он может быть синтаксически разобран двумя способами, приводящими к совершенно разным вычислениям:

if b0 then [for i := 1 step 1 until 100 do if b1 then S0

else S1]

и

if b0 then [for i := 1 step 1 until 100 do if b1 then S0]

else S1

Однако выйти из положения здесь достаточно просто: нужно использовать явный символ end в каждой конструкции, являющейся рекурсивной, и начинать с явного стартового символа, такого как if, while, for или case:

if b then S0 end

if b then S0 else S1 end