Что такое синтаксический сахар в программировании
Перейти к содержимому

Что такое синтаксический сахар в программировании

  • автор:

Что такое синтаксический сахар

Иногда на форумах и в комментариях опытных коллег-программистов можно услышать что-то вроде «Это просто синтаксический сахар, не обращай внимания». Давайте разберёмся, что это такое, зачем оно нужно и откуда такое название.

Что такое синтаксический сахар

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

Можно сделать код короче

Проще всего синтаксический сахар показать на примерах. Допустим, у нас значение одной переменной зависит от другой:

// исходная переменная var st = "true"; // если она истинна if (st == "true") < // то присваиваем второй переменной 'Y' var hasName = 'Y'; >else < // иначе присваиваем второй переменной 'N' var hasName = 'N'; >;

Этот же самый фрагмент можно записать короче, используя синтаксический сахар — тернарный оператор, который обрабатывает сразу три параметра:

hasName = name ? ‘Y’ : ‘N’;

Этот код делает всё то же самое:

  1. Проверяет, в name — истина или ложь.
  2. Если истина — присваивает переменной hasName значение ‘Y’.
  3. Иначе присваивает ей значение ‘N’.

Логика работы и действия остались точно такими же, но второй код получился компактнее, чем второй, хотя для новичка он выглядит гораздо сложнее.

Сделать код проще

Есть сахар, который, наоборот, делает код проще. Например, вот классический способ организовать цикл, чтобы вывести все его элементы на экран:

// объявляем простой цикл, чтобы вывести все элементы массива for (let i = 0; i

А вот то же самое, но с синтаксическим сахаром:

for (const element of massiv)

Здесь сразу понятно, что мы перебираем все значения массива massiv, кладём их в переменную element и выводим её на экран.

Ещё примеры синтаксического сахара

В большинстве случаев мы даже не задумываемся над тем, что используем синтаксический сахар в своём коде. Но часто с ним удобнее, чем без него:

Например, вот классический способ сделать объект в JavaScript:

var obj = new Object();

А вот более короткий вариант с сахаром:

Первая строчка — классический способ завести пустой массив, вторая — более привычный сахарный способ:

var arr = new Array();
var arr = [];

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

var regex = new RegExp(‘something’);
var regex = /something/;

А вот пример чистого сахара. Мы объявляем анонимную функцию, и тут же её выполняем:

В каких языках есть синтаксический сахар

Почти во всех языках программирования есть сахар, причём чем высокоуровневее язык, тем больше сахара можно в нём встретить. Меньше всего сахара в Ассемблерах и в странных языках типа Brainfuck.

Обязательно ли использовать сахар в коде

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

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

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

Синтаксический сахар (англ. syntactic sugar ) — термин, обозначающий дополнения синтаксиса языка программирования, которые не добавляют новых возможностей, а делают использование языка более удобным для человека.

Определение

«Синтаксический сахар» — это любой элемент синтаксиса языка программирования, который даёт программисту альтернативный способ записи другой, уже имеющейся в языке синтаксической конструкции, и при этом является более удобным, или более кратким, или похожим на другой распространённый способ записи, или помогает писать программы в хорошем стиле. С формальной точки зрения синтаксический сахар ничего не меняет и выразительности языку не прибавляет, однако может заметно облегчить программисту описание некоторых операций. Одновременно синтаксический сахар, особенно при его неумеренном применении, может ухудшать читаемость кода и усложнять его поддержку. Конструкции, являющиеся синтаксическим сахаром, могут легко транслироваться в конструкции основного синтаксиса.

Необходимо отметить, что понятие синтаксического сахара во многом условно. Его использование предполагает, что из всего множества синтаксических конструкций можно выделить некоторый «базовый набор», обеспечивающий всю функциональность языка, и тогда дополнительные синтаксические средства, которые при желании можно выразить с помощью базового набора, и будут для данного языка синтаксическим сахаром. Однако многие конструкции являются взаимозаменяемыми, и далеко не всегда можно определённо сказать, какие именно из них являются базовыми, а какие — дополнительными. Например, в языке Модула-2 есть четыре вида циклов: цикл с предусловием, цикл с постусловием, цикл с шагом и безусловный цикл. Теоретически, первые три вида циклов могут быть легко выражены через последний. Являются ли они, в таком случае, синтаксическим сахаром? Обычно так не говорят, хотя формально под вышеприведённое определение они попадают.

Примеры

Массивы в Си

Массивы в Си представляют собой блоки в памяти. Доступ к элементам массива производится через указатель на начало блока памяти (то есть, на начало массива) и смещение элемента относительно начального адреса. Это может быть записано без использования специального синтаксиса для массивов ( a — указатель на начало массива, i — индекс необходимого элемента, size — размер элемента данного типа в памяти): *(a + i * size) , но непосредственные операции с адресами в памяти и смещениями являются большим источником ошибок программистов, поэтому язык предоставляет специальный синтаксис: a[i] . Кроме того, для массивов с size = 1 есть возможность обратиться к i -му элементу массива уж совсем экзотическим способом: i[a] , что аналогично a[i] , так как значение указателя i+a , очевидно, равно a+i .

Тернарная операция в Си

Другой известный пример специализированной языковой конструкции — тернарная условная операция языка Си ?: . Следующие два фрагмента кода делают одно и тоже:

int fn(); int a = 1; int b; if (a > 0) b = fn(1); else b = fn(2); 
int fn(); int a = 1; int b = fn((a > 0)? 1 : 2); 

Причина введения такой операции — желание вставлять проверку простых условий прямо в выражения и возможность прямо указать компилятору, что результатом проверки условия будет единственное значение. Конструкция действительно сокращает запись, но вот по поводу её удобства мнения могут быть разными. Многие считают, что сокращение записи в данном случае не окупает ухудшение читаемости кода.

Переопределение операторов

К синтаксическому сахару можно отнести и переопределение операторов, поддерживаемое многими языками программирования. В принципе, любая операция может быть оформлена как процедура (функция, метод). Переопределение операторов позволяет выполнять операции, созданные программистом, внешне так же, как и встроенные в язык.

Свойства

Ещё одним примером синтаксического сахара является концепция «свойств», поддерживаемая многими современными языками программирования. Имеется в виду объявление в классе псевдополей, которые внешне ведут себя как поля класса (имеют имя, тип, допускают присваивание и чтение), но в действительности таковыми не являются. Каждое обращение к свойству преобразуется компилятором в вызов метода доступа. Свойства совершенно не являются необходимыми (методы доступа можно вызывать и непосредственно) и используются исключительно для удобства, поскольку код с использованием свойств выглядит несколько проще и понятнее.

Критика

Не все программисты считают наличие синтаксического сахара в языках программирования и использование его программистами благом. Известна точка зрения Никлауса Вирта, которую разделяет часть программистского сообщества: согласно ей, любое расширение языка, не вызванное необходимостью, ухудшает его, так как приводит к усложнению транслятора и, соответственно, к понижению его надёжности и производительности. Одновременно возрастает сложность изучения языка и сложность сопровождения программ. Кроме того, сам факт наличия дополнительных синтаксических средств часто играет провоцирующую роль: он побуждает программиста прибегать к различным синтаксическим трюкам вместо того, чтобы глубже анализировать задачу и реализовывать более эффективные алгоритмы. Эти взгляды отразились в языках семейства Оберон, очень простых и практически лишённых синтаксического сахара.

Известен афоризм Алана Перлиса: «Синтаксический сахар вызывает рак точек с запятой». Точка с запятой («;»), являясь обязательной частью большинства популярных языков программирования, даже если в новом языке бесполезна, оставляется как необязательный элемент, так как большинство программистов имеют прочную привычку её использования. В оригинале афоризм обыгрывает созвучие английских слов semicolon (точка с запятой) и colon, последнее из которых означает не только двоеточие, но и толстый кишечник (colon cancer — рак толстого кишечника).

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

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

В противоположность «синтаксическому сахару» в понятие «синтаксическая соль» (англ. syntactic salt ) [1] на жаргоне хакеров обозначает конструкции в языке программирования, которые необходимо употреблять при выполнении потенциально небезопасных действий. Таким образом, используя их, программист подтверждает, что сомнительное действие предпринято им сознательно, а не является случайной ошибкой или результатом непонимания. Так же, как «синтаксический сахар» не добавляет языку выразительности, «синтаксическая соль» не расширяет возможности языка и не нужна транслятору для корректной компиляции программы; она предназначена исключительно для людей, пользующихся данным языком. Классическим примером общеизвестной и широко применяемой «синтаксической соли» являются имеющиеся почти в любом языке со статической типизацией встроенные команды преобразования типов данных. Формально эти команды излишни (что доказывает классический язык Си, где любое преобразование типов допустимо и выполняется автоматически), но в языках, где их применение обязательно, программист вынужден каждый раз обращать внимание на то, что он выполняет потенциально опасное смешение типов (которое часто указывает на логическую ошибку в программе). В зависимости от строгости языка программирования использование «синтаксической соли» может быть обязательным или факультативным. В первом случае транслятор воспринимает её отсутствие как синтаксическую ошибку, во втором — выдаёт при трансляции предупреждение, которое программист может проигнорировать. В отличие от «синтаксического сахара», который расширяет свободу выражения программиста, «синтаксическая соль» её сужает, требуя «без причины» писать длинные конструкции.

В Jargon File написано: «синтаксическая соль вредна, поскольку повышает артериальное давление хакера». Действительно, при написании небольших программ, создаваемых и поддерживаемых одним человеком, предосторожности могут показаться излишними, однако при промышленной разработке крупных программных комплексов, поддерживаемых большими коллективами программистов (зачастую, к тому же, не самой высокой квалификации), «синтаксическая соль» помогает не ошибаться в разработке и эффективнее разбираться в коде, написанном другими разработчиками.

  • Директива override в Delphi явно указывает на то, что помеченный ею метод подменяет виртуальный метод класса-родителя. Наличие этой директивы требует от компилятора проверить соответствие сигнатуры подменяющего и подменяемого метода, так что при изменении в базовом классе программист будет вынужден внести те же изменения в классы-потомки, иначе программа не будет компилироваться.
  • Операция reinterpret_cast в C++ обеспечивает небезопасное преобразование типа. Операция не производит никакого кода, она лишь обходит контроль типов. Единственный смысл её использования — напоминание, что подобное небезопасное преобразование типов использовано намеренно.

Примечания

Литература

Как синтаксический сахар может сыграть с вами злую шутку

Хочу рассказать вам историю о том, как синтаксический сахар может отнять у вас несколько часов и привести к ошибкам на продакшене. Так же разберу причины самих ошибок и постараюсь найти варианты, как можно было бы их избежать.

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

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

В нашей команде используется язык C#, поэтому мой рассказ будет про его синтаксис.

Синтаксический сахар заменяет длинные и часто используемые конструкции кода, делает их более короткими и быстро читаемыми, облегчает и ускоряет разработку.

Здесь стоит отметить и другое мнение: существуют люди, которые считают, что синтаксический сахар только усложняет код, делая его менее читаемым.

Я придерживаюсь данного мной определения, хотя опыт показал, что не всё так однозначно. Разберем на примерах:

Примеры:

  • Конструкция new () заменяет new List()
  • Оператор += заменяет конструкцию
    • number += 1 =>
    • number = number + 1
    • foo ??= «Строка была равна null» =>
    • foo = foo ?? «Строка была равна null» =>
    • foo = foo is null ? «Строка была равна null» : foo =>
    • if (foo is null)
      foo = «Строка была равна null»;
      >

    Эти примеры лишь малая часть всех тех конструкций, которые иcпользуются в C#. С каждой новой версией языка появляется всё больше новых конструкций и нужно пристально следить, чтобы ничего не упустить.

    Неожиданные Null Reference Exception

    Итак, перейдем к истории. Всё началось с того момента, когда в нашем проекте начали «выстреливать» ошибки NRE . По стек-трейсу было ясно, что код «падает» при инициализации класса. Ниже представлен фрагмент кода, приближенный к тому, что был у нас в проекте.

    . var result = new ExampleClass < ExString = "Тут не должно быть взрыва", ExList = < 0, 1 >, ExString2 = "И тут", ExInt = 24 >; . 

    NRE выбрасывалось на строке var result = new ExampleClass , которая, в теории, не должна вызывать такую ошибку. Отсюда стало очевидно, что следует обратить внимание на то, как инициализируются поля объекта.

    Вот как выглядел класс, который мы пытались инициализировать:

    public class ExampleClass < public string? ExString < get; set; >public List? ExList < get; set; >public string? ExString2 < get; set; >public int ExInt < get; set; >>

    Наверное, я оставил очень прозрачные подсказки в коде, чтобы вы смогли догадаться, из-за чего выбрасывалась ошибка. Но в моменте было совсем не ясно, особенно когда ты пытаешься быстро разобраться в ситуации из-за ошибок на продакшене.

    Пояснение

    Можно обратить внимание на весьма странный синтаксис в коде.

    . var result = new ExampleClass < . ExList = < 0, 1 >, . >; . 

    Выше я приводил пример того, как конструкция new() заменяет new List() . Можно заметить, что уж очень похоже на new() .
    Первый раз, глядя на эту конструкцию, в голову совсем не приходит мысль о том, что тут что-то не так. Скорее возникает мысль: «Наверное, это новый синтаксис». После 10 минут интенсивного просмотра кода было принято решение заменить на new() . И, о чудо, ошибки исчезли.

    Но причём тут NRE? А всё дело в том, что заменяет конструкцию .Add() И вот эти два блока кода оказываются идентичными:

    // 1 var result1 = new ExampleClass < ExList = < 1, 2 >, ExString = "Привет", ExInt = 24 >; // 2 var result2 = new ExampleClass < ExString = "Привет", ExInt = 24 >; result.ExList.Add(1); result.ExList.Add(2);

    Так как ExList при инициализации равен null , то при попытке вызывать null.Add() мы получаем NRE .

    Почему такое произошло?

    Лично я вижу здесь несколько причин. Во-первых, в нашей команде и вокруг неё этот синтаксис не так популярен, с ним редко кто сталкивается. Во-вторых, IDE никак не подсвечивает такую простую NRE , хотя поле было помечено как nullable, и такое можно было бы подсветить.

    Как этого избежать?

    Самое главное — быть внимательным и проверять код. Можно попробовать следить за актуальными конструкциями, но, по моему опыту, это сделать весьма проблематично. Как ни странно, хоть IDE в этом случае подвело, но оно все равно умеет замечать большинство таких проблем. Именно поэтому стоит прислушиваться к его предупреждениям.

    Заключение

    В заключении хочу сказать, что несмотря на такие ситуации, синтаксический сахар остается мощным инструментом и приносит больше пользы, чем вреда. Чтобы избежать таких проблем, важно следить за глубоким пониманием того, как работает ваш код, а не только за тем, как он выглядит. Регулярный код-ревью и обмен опытом с коллегами помогут вам выявлять и предотвращать подобные ошибки заранее.

    P.S.

    Это одна из первых моих статей на Habr, и я был бы благодарен за вашу конструктивную критику и обратную связь.

    • синтаксический сахар
    • программирование
    • c#
    • ошибки программистов
    • ошибки и грабли
    • ошибки в коде
    • решения

    Что означает разговорное выражение «синтаксический сахар»?

    я в своё время написал вопрос для викторины об этом термине. Постарался кратко и внятно сформулировать: «ЭТО дополнение синтаксиса языка программирования не добавляет новых возможностей, а только облегчает использование языка человеком.» (19 букв)

    6 мая 2016 в 15:15

    3 ответа 3

    Сортировка: Сброс на вариант по умолчанию

    Словосочетание «синтаксический сахар» используется для описания синтаксических конструкций, которые вводятся только для упрощения реализации чего-либо (сокращения объема кода, повышения читаемости и т.д.) в том или ином языке.

    При этом, без синтаксического сахара вполне можно обойтись, но реализация без его использования получится более громоздкой (сложной, непонятной, . ).

    Типичный пример — новый синтаксис для стрелочных функций в ES6:

    var f = x => x*x; 

    В ES5 эту конструкцию можно записать так:

    var f = function(x)

    Для любителей JS отмечу, что стрелочные функции еще и контекст вызова «привязывают» автоматически, но в данном конкретном примере это не существенно.

    Отслеживать
    ответ дан 6 мая 2016 в 14:44
    Dmitriy Simushev Dmitriy Simushev
    18k 5 5 золотых знаков 49 49 серебряных знаков 85 85 бронзовых знаков
    «стрелочная функция» это новое название лямбда-функции? )
    6 мая 2016 в 17:33

    «Стрелочная функция» — это подвид анонимных (лямбда) функций в JS. В англоязычном варианте устоявшийся термин «arrow function». А называется она так по характерной стрелке => в синтаксисе определения

    6 мая 2016 в 17:37
    а почему подвид, чем отличаются от прочих?
    6 мая 2016 в 17:52

    Немного другой синтаксис + автоматическая привязка this . Насколько мне помнится, к ним так же не применим метод Function.prototype.bind

    6 мая 2016 в 17:53
    Ага, примерно понял. Спасибо )
    6 мая 2016 в 17:55

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

    В данном случае «тернарный оператор if» полностью совпадает с типичным if-else и присваиванием, но немного короче.

    a = x != 0 ? a/x : 0; 

    аналогично, но короче чем

    if(x != 0) < a /= x; >else

    Отслеживать
    ответ дан 6 мая 2016 в 14:47
    Alex Krass Alex Krass
    17.7k 2 2 золотых знака 25 25 серебряных знаков 52 52 бронзовых знака

    Читаю книгу «Вы не знаете JS: This и Прототипы Объектов. Глава 4: Смешивая объекты «классов»» И наткнулся на ваш вопрос. Вот небольшой пример JS и сахара, который вы еще не раз застанете и будете возмущенны, если привыкли к ООП и классам в других языках.

    Но значит ли это, что в JavaScript действительно есть классы? Строго и однозначно: Нет.

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

    Хотя у нас и может быть синтаксис, похожий на классы, это больше похоже на то, что механика JavaScript борется против того, чтобы вы использовали шаблон проектирования class. Так как под капотом механизмы, которые вы строите, работают совсем по-другому. Синтаксический сахар и (очень широко используемые) JS библиотеки для работы с «классами» проходят долгий путь скрывая эту реальность от вас, но рано или поздно вы столкнетесь с тем, что классы которые у вас есть в других языках не похожи на фейковые «классы», которые мы создаем себе в JS.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *