Введение

Синтаксис языка программирования, разработанный для удобства использования. В информатике синтаксический сахар — это синтаксис в языке программирования, предназначенный для облегчения чтения или выражения. Он делает язык "слаще" для человека: вещи можно выразить более ясно, лаконично или в альтернативном стиле, который может быть предпочтительнее. Синтаксический сахар обычно является сокращением для часто используемой операции, которую также можно выразить в альтернативной, более многословной форме. Программист может выбрать, использовать более короткую или более длинную форму, но обычно выбирает более короткую, так как она короче и легче для набора и чтения. Например, многие языки программирования предоставляют специальный синтаксис для обращения к элементам массива и их изменения. В абстрактном представлении обращение к элементу массива — это процедура с двумя аргументами: массив и вектор индексов, которую можно выразить как `get array(Array, vector(i,j))`. Вместо этого многие языки предоставляют синтаксис, такой как `Array[i,j]`. Аналогично, изменение элемента массива — это процедура с тремя аргументами, например, `set array(Array, vector(i,j), value)`, но многие языки также предоставляют синтаксис, такой как `Array[i,j] = value`. Конструкция в языке считается синтаксическим сахаром, если её можно удалить из языка без изменения его функциональности и выразительной силы. Языковые процессоры, включая компиляторы и статические анализаторы, часто преобразуют конструкции с синтаксическим сахаром в их более многословные эквиваленты перед обработкой, процесс, иногда называемый "десахаризацией".

Происхождение

Термин «синтаксический сахар» был введен Питером Дж. Лэндином в 1964 году для описания поверхностного синтаксиса простого языка программирования, подобного ALGOL, который был семантически определен в терминах аппликативных выражений лямбда-исчисления, с акцентом на лексической замене λ на "where". Впоследствии языки программирования, такие как CLU, ML и Scheme, расширили это понятие, чтобы оно относилось к синтаксису внутри языка, который можно было бы определить в терминах ядра языка, состоящего из основных конструкций; удобные, более высокоуровневые возможности можно было бы «разсахарить» и разложить на это подмножество. Это, по сути, стандартная математическая практика построения из примитивов. Развивая различие, сделанное Лэндином между основными языковыми конструкциями и синтаксическим сахаром, в 1991 году Маттиас Феллейзен предложил кодификацию «выразительной силы» для согласования с «общепринятыми представлениями» в литературе. Он определил «более выразительным» как то, что без рассматриваемых языковых конструкций программу пришлось бы полностью перестраивать.

Примечательные примеры

В COBOL многие промежуточные ключевые слова являются синтаксическим сахаром, который можно необязательно опустить. Например, предложение `MOVE A B.` и предложение `MOVE A TO B.` выполняют точно такую же функцию, но второе делает выполняемое действие более понятным. Операторы расширенного или составного присваивания: например, `a += b` эквивалентно `a = a + b` в C и подобных языках, при условии, что `a` не имеет побочных эффектов, например, если `a` является обычной переменной. Некоторые языки, такие как Python, могут допускать перегрузку операторов расширенного присваивания, поэтому они могут вести себя иначе, чем стандартные. В Perl, `unless (condition) { }` является синтаксическим сахаром для `if (not condition) { }`. Кроме того, любое выражение может следовать за условием, поэтому `statement if condition` эквивалентно `if (condition) { statement }`, но первое более естественно форматируется в одну строку. В языке C обозначение `a[i]` является синтаксическим сахаром для `*(a + i)`. Аналогично, обозначение `a->x` является синтаксическим сахаром для доступа к членам с использованием оператора разыменования (`*a`).x. В C# оператор `using` гарантирует правильную утилизацию определенных объектов. Компилятор преобразует этот оператор в блок `try...finally`. Язык C# позволяет объявлять переменные как `var x = expr`, что позволяет компилятору выводить тип `x` из выражения `expr`, вместо того, чтобы требовать явного объявления типа. Аналогично, C++ позволяет использовать `auto x = expr` начиная с C++11, а Java – `var x = expr` начиная с Java 11. В Python – списочные выражения (например, `[x*x for x in range(10)]` для списка квадратов) и декораторы (например, `@staticmethod`). В Haskell строка, заключенная в кавычки, семантически эквивалентна списку символов. Дополнительное расширение языка `OverloadedStrings` позволяет строковым литералам создавать значения других типов, например `Text`. В коллекции пакетов tidyverse для R, пайп (обозначается `%>%`) указывает, что данные (или результат функции), предшествующие пайпу, будут служить первым аргументом для функции, следующей за пайпом. Таким образом, `x %>% f(y)` эквивалентно `f(x, y)`. В SQL простое `JOIN` эквивалентно `INNER JOIN`, последнее уточняет, что оператор соединения является конкретно внутренней операцией соединения, а не внешней. Аналогично, можно опустить `OUTER` из `LEFT OUTER JOIN`, `RIGHT OUTER JOIN` и `FULL OUTER JOIN`. Вызов метода в объектно-ориентированных языках в форме `myObject.myMethod(parameter1, parameter2, parameter3)` является синтаксическим сахаром для вызова глобальной функции как `myMethod(myObject, parameter1, parameter2, parameter3)`. Ссылка на объект передается как скрытый аргумент, обычно доступный внутри метода как `this`. Параметр, передаваемый по ссылке, является синтаксическим сахаром для фактической передачи указателя в качестве параметра, но синтаксически обрабатывается как сама переменная, чтобы избежать постоянного разыменования указателя в коде внутри функции. В Java объявление `import` позволяет компилятору находить классы, которые не указаны в других случаях с использованием полных имен. Например, `import javax.swing.*;` позволяет программисту ссылаться на объект Swing, такой как `javax.swing.JButton`, используя более короткое имя `JButton`. В версии ES6 JavaScript стрелочные функции имеют короткую форму `(x) => x + 1`, которая эквивалентна более длинной форме `(x) => { return x + 1; }`. В Scala тройные вопросительные знаки (`???`) эквивалентны `throw new NotImplementedError`. Это полезно для обозначения места для кода, который еще не был написан.

Критика

Некоторые программисты считают, что эти элементы удобства синтаксиса либо неважны, либо откровенно легкомысленны. В частности, специальные синтаксические конструкции делают язык менее единообразным, а его спецификацию – более сложной, и могут создавать проблемы по мере роста и усложнения программ. Эта точка зрения особенно распространена в сообществе Lisp, поскольку Lisp обладает очень простым и регулярным синтаксисом, и поверхностный синтаксис может быть легко модифицирован. Например, Алан Перлис однажды остроумно заметил в "Эпиграммах о программировании", ссылаясь на языки с использованием скобок, что "Синтаксический сахар вызывает рак точек с запятой".

Синтаксическая соль

Эта метафора была расширена введением термина "синтаксическая соль", обозначающего особенность, призванную затруднить написание некачественного кода. В частности, синтаксическая соль – это препятствие, которое программистам необходимо преодолеть, чтобы продемонстрировать понимание происходящего, а не просто выразить действие программы. В C#, при сокрытии унаследованного члена класса, компилятор выдает предупреждение, если не используется ключевое слово `new` для явного указания намеренного сокрытия. Чтобы избежать потенциальных ошибок, связанных с синтаксическим сходством оператора `switch` с языками C или C++, в C# требуется оператор `break` для каждой непустой метки `case` (если не используются `goto`, `return` или `throw`), даже несмотря на то, что не допускается неявное проваливание в следующий `case`. (Использование `goto` и указание следующей метки обеспечивает поведение, аналогичное проваливанию в C/C++.) Синтаксическая соль может свести на нет свою полезность, делая код трудночитаемым и, следовательно, ухудшая его качество – в крайних случаях, основная логика кода может оказаться короче, чем накладные расходы, необходимые для соответствия требованиям языка. Альтернативой синтаксической соли является генерация предупреждений компилятором при высокой вероятности того, что код является результатом ошибки – практика, широко распространенная в современных компиляторах C/C++.

Синтаксический сахарин

Другие расширения — синтаксический сахарин и синтаксический сироп, то есть излишний синтаксис, который не упрощает программирование.

Сахарные сорта

Типы данных с основной синтаксической поддержкой называются "типами с синтаксическим сахаром". Распространенные примеры включают строки, заключенные в кавычки, фигурные скобки для объектов и записей, и квадратные скобки для массивов.