вторник, 10 июля 2007 г.

Перекрыть Енисей или перекрыть функцию

Этот текст был написан несколько лет назад и тогда же отправлен в какой-то компьютерный журнал. Публикации, как и какого-либо ответа, не последовало - возможно, из-за чрезмерной резкости высказываний. Мне кажется, тем не менее, что текст выглядит вполне актуальным и посегодня.

Несмотря на это, я бы, наверное, все-таки не стал выкладывать этот текст, если бы не прогресс в деле выпуска перевода Стандарта C++. Можно сказать, что мое мнение о том, каков должен быть правильный перевод, выскзано здесь со всей определенностью.

Обсуждая со студентами вопросы программирования на Си++, часто приходится сталкиваться с достаточно вольным обращением с терминологией. В основном, эти вольности проистекают от прямой транслитерации англоязычных терминов из западных описаний и руководств и недостаточного знакомства с квалифицированными переводами. Со временем я научился терпимо относиться к подобной "терминологии", помня, что устная речь, в том числе и профессиональная, может несколько отличаться от письменной в сторону большей свободы. Я даже научился не морщиться от "перекрытых функций"; иной раз, правда, не выдерживаю: "Функция - не Енисей, ее не перекрывают". Но, честно говоря, я никак не ожидал подобного от переводчиков Бьярна Строуструпа!

Недавно вышло в свет долгожданное третье издание Б. Строуструпа "Язык программирования C++" (издательство "БИНОМ"). Впечатление от оригинальной версии книги создалось весьма положительное, так что появление перевода следует всячески приветствовать.

Все бы хорошо, однако… В предисловии "От редакции русского издания", в частности, представлен редакционный подход к переводу терминологии. Прошу прощения за резкость, но создается впечатление, что книгу переводили те самые студенты. Подобную легкость и святую уверенность первопроходцев можно наблюдать, пожалуй, только у этой братии. Цитирую:

Слово "statement" принято переводить на русский язык как "оператор". Мы привыкли к тому, что if, while, case и т. д. - это операторы. Увы, в контексте С++ такой перевод неприемлем. Дело в том, что в С++ слово "operator" (которое и переведено как "оператор") имеет совсем другое значение. Оно применяется для обозначения сложения (оператор +), разыменования (оператор *), выяснения размера (оператор sizeof ()) и в других подобных случаях…

…Что же касается термина "statement", то из предлагаемых различными словарями вариантов "утверждение", "предложение" и "инструкция" мы избрали последний, так как он, по-видимому, лучше всего соответствует сущности обозначаемых словом "statement" конструкций С++ и, кроме того, периодически встречается в книгах и документации в нужном значении…

Си++ - типичный операторный язык; в этом смысле он ничем не отличается от своих предшественников и других алгоритмических языков программирования - Алгол-60, Паскаль, Си, Ада. Тот факт, что в Си++ присваивание считается бинарной операцией, вырабатывающей значение, не меняет существа дела - в Си ситуация точно такая же. Уже по одной этой причине нет решительно никаких оснований вводить для традиционных операторов - условного, цикла и т.д.- новое название. И уж совсем диким выглядит конкретный вариант перевода для английского statement - инструкция! Конечно, любой англо-русский словарь добросовестно перечислит весь спектр возможных значений для того или иного английского слова; наверное, в каком-нибудь из них и можно найти и такой вариант. Но это же не основание для того, чтобы выбрать для фундаментальной книги по программированию на Си++ слово, традиционно используемое - даже не для языка ассемблера, а в описании системы команд какого-нибудь процессора! Instruction set - устойчивое сочетание в книгах о процессорных архитектурах.

Если же язык программирования построен на иных принципах, как, например, Алгол-68 или (если обратиться к отечественному опыту) Эль-76, тогда становится оправданной иная, соответствующая природе этих языков терминология. Оба упомянутых языка не являются операторными языками: почти любая их конструкция может вырабатывать значение. Поэтому такие их "строительные элементы", как, например, условие или выбор традиционно переводятся или называются предложениями: условное предложение, выбирающее предложение и т.д.

На самом деле авторы перевода тут же простодушно поясняют свой выбор. Дело в том, что так они надеялись решить проблему с другим понятием языка, выражаемым словом operator. Действительно, как же иначе перевести это слово, как не побуквенно! Вот и получается, что слово "оператор" уже занято… И statement становится - инструкцией.

Между тем, в истории языков программирования, кажется, не было ни одного случая, чтобы сложение, вычитание, сравнение и другие подобные действия назывались в русском языке как-либо иначе, нежели операция. Поэтому трактовка слова operator совершенно однозначна. Если для statement, действительно, часто используются различные варианты перевода, и вариант "оператор" более предпочтителен, в основном, как уважительное следование традиции, то, чтобы выговорить "оператор сложения", необходимы специальные услилия по деформированию русского языка. Да, в некоторых областях математики английское operator переводят как "оператор", но для программирования это совершенный нонсенс, впервые появишейся в устной речи тех самых студентов, познававших Си++ по текстам оперативной помощи.

В результате получаем следующий пассаж авторов перевода:

В частности, = - это оператор присваивания, семантику которого можно изменить путем перегрузки, а вот запись a = b; является инструкцией присваивания, семантика которой неизменна, фиксирована языком и состоит в вызове (возможно перегруженного) оператора присваивания с аргументами a и b.

Запись a = b; не может быть "инструкцией присваивания", даже если иметь в виду, что под "инструкцией" понимается statement. По Стандарту эта конструкция называется expression-statement (оператор-выражение, согласно переводу предварительной версии стандарта, см. конец заметки). Иными словами, присваивание (операция присваивания!) - это частный случай выражения, а выражение в позиции, не вырабатывающей значения, считается именно оператором-выражением. Семантика же этой конструкции вовсе не обязательно заключается в вызове какой-либо функции; возможно (для базовых типов) и непосредственное копирование значения. Кстати, как можно вызвать "оператор присваивания"? Вроде бы, вызвать можно только функцию… На самом деле авторы перевода имели в виду функцию-операцию (в Стандарте - operator function).

Далее авторы перевода пишут:

С учетом того, что большинство операторов С++ допускает перегрузку, синтаксически и семантически напоминающую (пере)определение функций, можно сказать, что операторы в С++ сродни функциям.

Сходство функций и операций - давно осознанный и освоенный наукой программирования факт. Скажем, в языке Clu, появление которого в свое время было воспринято как заметное событие, традиционные операции в инфиксной форме рассматривались как излишество, "синтаксический сахар", уступка привычкам, а первичной конструкцией считался как раз вызов функции. Так что приведенная выше цитата не имеет прямого отношения к выбранной терминологии. Отметим только некоторую словесную кашу: если "операторы в Си++ сродни функциям", то почему "перегрузка операторов", но "переопределение функций"? В оригинальных английских текстах используется одно и то же слово overloading…

А дело в том, что авторов ведет дурная традиция буквального перевода этого слова, бытующая в устной речи, в которой используются оба вульгаризма. Не говоря уже о том, что и тот, и другой "термины" явно неблагозвучны и отягощены посторонними ассоциациями, они семантически не вполне корректны. Например, если говорить о "переопределении", то точный смысл этого слова заключается в том что одна функция "переопределяет" собой некоторую другую, заданную раньше, так, что первая функция становится недоступной (невидимой). Ведь "переопределяет" означает буквально "определяет заново", не так ли? В то же время все понимают, что соответствующее свойство Си++ заключается как раз в том, что с некоторого момента в текущей области действия становятся доступны для использования несколько одноименных функций (или функций-операций) одновременно. Так что наиболее естественным было бы назвать такие функции совместно используемыми, что и сделано в книге, указанной в конце заметки.

Хочется высказать замечание общего характера. В информатике и, в частности, в программировании сложилась какая-то странная ситуация. Иногда создается ощущение, что история вычислительного дела началась с IBM-овских персоналок (до них, как всем известно, компьютеров не было), язык Си++ был первым дерзновенным рывком от ассемблера к сияющим вершинам объектно-ориентированного программирования, а первой компьютерной книгой, переведенной на русский язык, был серый том Питера Нортона…

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

Так что, читая сейчас очередной "вольный перевод" какой-нибудь новинки и натыкаясь взглядом на многочисленные "хэндлы", "директории" и "перекрытые функции", я точно знаю, что переводчик и редактор не читали ни одной книги по программированию, вышедшей ранее 1990 г., историю информатики ведут от голубых окон Norton Commander и даже не подозревают о том, что решительно все термины, для которых они упоенно придумывают собственные толкования, уже имеют выбранные профессионалами, вполне определенные, обоснованные и исторически прижившиеся русские эквиваленты.

Возвращаясь к книге Строуструпа, не могу не сказать, что ее переводчики при желании (и при наличии простого уважения к своим предшественникам) могли обратиться к действительно грамотно выполненному переводу описания предварительной версии Стандарта Си++, написанному тем же автором (Эллис М. и Строуструп Б. Справочное руководство по языку программирования C++ с комментариями: пер. с англ.- М.: Мир, 1992). Этот перевод сделан специалистами из новосибирского Академгородка, которые сами являются профессиональными и высококлассными программистами. Поэтому в нем вы не найдете ни "инструкций присваивания", ни "операторов сложения", ни "перегруженных функций"…

Кстати, в этой же книге для терминов declaration и definition используются, соответственно, переводы "объявление" и "описание". Неужели и здесь было совершенно необходимо непременно сказать свое слово, переведя definition как "определение"?

1 комментарий:

Stan комментирует...

Дело в том, что в математике понятие «оператор» – это не калька с английского языка. В математике термин «оператор» обозначает функцию, вид который зависит от раздела математики. Так, например, термин «матричный оператор» слышат все студенты технических вузов (курсе на первом или втором) и это не является деформацией русского языка. В записи y = Ax, А – называется оператором и под ним может подразумеваться любая функция, которая отображает множество X во множество Y.

В общеупотребимых английских словарях понятие оператора отличается от операции.
Моя печатная копия Оксфордского словаря определяет термин operator для математики как: a symbol or function denoting an operation (e.g. *, +), что соответствует определению в данной выше ссылке.

Поэтому семантически правильно говорить «оператор», когда мы говорим о символе или о функциональном отображении, которое определяет этот символ. И семантически более корректно говорить «операция», когда речь идет о конкретных операндах и результатах: «Результат операции сложения двух чисел есть число».

Что же касается C++, то мне доподлинно не известно, о чем думал Страуструп, когда вводил слово «operator», но можно сделать предположение. Исходя из того, что он написал в своей книге «Дизайн и эволюция С++», это было введено для переопределения семантики символа, например, + применительно к различным классам операндов. Переопределяется именно семантика символа, функция вызывается – это и есть оператор. А вот вызываемая функция уже как раз должна реализовать, в данном случае, операцию сложения значений двух своих операндов.

Данная строка является синтаксически правильной с точки зрения С++
Point operator * (Point pt, Matrix m);
Vector operator - (Point p1, Point p2);
Но с точки зрения математики эти примеры являются самыми настоящим отображениями.

На основе всего вышесказанного, считаю, что слово «operator» было выбрано достаточно правильно, и при переводе – необходимо употреблять слово «оператор», когда мы говорим, что мы определяем, и употреблять слово «операция», когда мы говорим о том, что мы выполняем.