Яка різниця між "Синтаксисом" та "Синтаксичним цукром"


45

Фон

На сторінці Вікіпедії про синтаксичний цукор зазначено:

В інформатиці синтаксичний цукор - це синтаксис в рамках мови програмування, який призначений для полегшення читання або вираження речей. Це робить мову "солодшою" для використання людьми: речі можна висловити більш чітко, стисло або в альтернативному стилі, який деякі можуть віддати перевагу.

Я не дуже розумію, в чому різниця між синтаксичним цукром і синтаксисом.

Я вдячний за те, що цукриста версія може бути більш чіткою, стислою, можливо, зварити якусь котельну плиту. Але я відчуваю, що на деякому рівні весь синтаксис по суті робить це, щоб сформувати абстракцію над тим, до чого збирається код.

З тієї ж сторінки Вікіпедії:

Мовні процесори, включаючи компілятори, статичні аналізатори тощо, часто розширюють цукрові конструкції на більш фундаментальні конструкції перед обробкою, процес, який іноді називають "знешкодженням".

Як мислительна вправа, якщо я вважаю, що "часто" в цьому висловлюванні означає "завжди": Якщо різниця полягала лише в тому, чи компілятор "знезаражує" синтаксис, перш ніж перейти до наступного етапу, то як може кодер, який не знає внутрішніх компілятора знаєте (або піклуєтеся), що таке синтаксис Sugar'd чи ні?

Дуже споріднене питання на цьому сайті "Суворе визначення синтаксичного цукру?" має відповідь, яка починається:

IMHO Я не думаю, що ви можете визначити синтаксичний цукор, оскільки ця фраза є BS і, ймовірно, буде використана людьми, які говорять про "справжніх програмістів", використовуючи "реальні інструменти" на "реальних операційних системах"

Що може вказувати на мене, що, можливо, немає великої різниці в кодері, що використовує мову? Можливо, різниця відчутна лише для письменника-укладача? Хоча можуть бути випадки, коли кодеру корисно використовувати мову, щоб знати, що знаходиться під кришкою синтаксичного цукру? (Але, можливо, насправді будь-який дискурс на цю тему має тенденцію використовувати цей термін як принаду полум'я?)

Серце питання

Отже ... коротка версія питання:

  • Чи є реальна різниця між синтаксисом та синтаксичним цукром?
  • Кому це важливо?

Додаткова їжа для думки

Бонус за протиріччя теми:

На сторінці Вікіпедії наведено приклад:

Наприклад, у мові С a[i]позначення є синтаксичним цукром для*(a + i)

Тоді як інша відповідь на вищезазначене пов'язане питання говорить про той же приклад:

Тепер розглянемо a[i] == *(a + i). Подумайте про будь-яку програму C, яка використовує масиви будь-яким змістовно.

І підсумовує, що:

[]Позначення полегшує цю абстракцію. Це не синтаксичний цукор.

Протилежний висновок для того ж прикладу!


9
У своїй відповіді на цитоване запитання я пояснюю, що синтаксичний цукор - це альтернативний синтаксис (до якогось синтаксису, який вже існує в мові), що полегшує висловлення деяких загальних ідіом, але не вводить нової семантики. У цьому сенсі синтаксичний цукор залежить від контексту (від мови, якою він використовується): однакові позначення можуть бути звичайним синтаксисом в одній мові, а синтаксичним цукром - в іншій. Чи допомагає вам це пояснення?
Джорджіо

7
Одна з проблем полягає в тому, що деякі люди, здається, думають, що «синтаксичний цукор» - це брудне слово, коли його немає. Кожна функція або клас, який ви додаєте до системи, можна вважати "синтаксичним цукром", оскільки вони полегшують вираження ідей, які вже були чітко вираженими мовою.
Joris Timmermans

Мабуть, це має значення для вас.
SShaheen

11
Зрештою, це все лише синтатичний цукор над електрикою.
Ентоні Пеграм

Відповіді:


34

Основна відмінність полягає в тому, що синтаксис - це граматика, визначена мовою, що дозволяє розкрити певну функціональність. Як тільки ви зможете перейти до цієї функціональності, будь-який інший синтаксис, який дозволяє вам робити те саме, вважається цукром. Це, звичайно, наштовхується на дивні сценарії щодо того, який із двох синтаксисів є цукром, тим більше, що не завжди зрозуміло, хто став першим.

На практиці синтаксичний цукор використовується лише для опису доданого до мови синтаксису для полегшення зручності використання, як, наприклад, створення інфіксованої lhs + rhsкарти lhs.Add(rhs). Я б вважав індексацію масиву С синтаксичним цукром.

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


"Як тільки ви зможете перейти до цієї функціональності, будь-який інший синтаксис, який дозволяє вам робити те ж саме, вважається цукром.": Цього недостатньо, щоб мати синтаксичний цукор, тому що тоді будь-яка інша програма, яка обчислює ту саму функцію, буде синтаксичним цукром . Цукрова програма та програма, що дезагарована, повинні мати однакову семантику .
Джорджіо

3
@Giorgio Як "ці дві програми обчислюють одну і ту ж функцію", відмінну від "ці дві програми мають однакову семантику"? Крім цього, ви орієнтуєтесь на програми, а не на синтаксичні елементи. Цілі програми не можуть бути синтаксичним цукром. Оператор, вид висловлювання тощо може бути синтаксичним цукром.

@Giorgio - Дійсно, я вважаю подібну функціональність з різною семантикою різною функціональністю. І так, може бути стрибок з обручем, як написання власного компілятора, який має ту саму семантику і називати це "цукром". Чесно кажучи, формального визначення такого неформального поняття не відбудеться.
Теластин

1
@Giorgio Знову ж таки, моя яловичина не з вашим рівнем еквівалентності, а в тому, що ви намагаєтесь застосувати концепцію синтаксичного цукру до програм. Термін не стосується цілих програм! Залежно від вашого визначення, це або лише атомні будівельні блоки, або лише короткі фрагменти програми (перший, здається, покриває> 80%, але я не впевнений, що він охоплює все, що зазвичай вважається синтаксичним цукром).

3
@Giorgio Наприклад, цілі програми ;-) Або щось досить велике, що обидві рецептури включають кілька неспоріднених мовних ключових слів. Щось, що я ніколи не трактував як синтаксичний цукор if (a) return blah; ...проти result_type res; if (a) res = blah; else {...}; return res;. Вам потрібно буде взяти на себе конкретні мови та отримати надзвичайно мову-юрист (часто до дрібної оперативної семантики), щоб знайти будь-яку різницю між цими програмами.

10

Синтаксис - це те, що мовний процесор використовує, щоб зрозуміти, що означає конструкції мови. Конструкти, які вважаються синтаксичним цукром, також повинні тлумачитися мовним процесором і, таким чином, є частиною синтаксису мов.

Що відрізняє синтаксичний цукор від решти синтаксису мови, це те, що можна було б видалити синтаксичний цукор з мови, не впливаючи на програми, які можна записати мовою.

Щоб дати більш формалістичне визначення, я б сказав

Синтаксичний цукор - це частини синтаксису мови, ефекти яких визначаються з точки зору інших синтаксичних конструкцій у мові.

Це жодним чином не означає приниження синтаксичного цукру або мов, які його містять, оскільки використання синтаксичного цукру часто призводить до програм, чий намір зрозуміліший.


"Немає можливості остаточно сказати" це синтаксичний цукор і це синтаксис ", оскільки синтаксичний цукор є частиною синтаксису мови.": Неправдиво. Саме дизайнер мови вводить якийсь синтаксис як синтаксичний цукор для якоїсь конструкції, яка вже є в мові і має синтаксис. Синтаксичний цукор, як правило, є спеціальним (менш загальним), але більш читабельним / зручним у використанні.
Джорджіо

@Giorgio: Я перефразував свій перший абзац, оскільки це було трохи незручно. Але я не згоден, що синтаксичний цукор зазвичай додається спеціально. Найвідоміший біт синтаксичного цукру, ймовірно, є ->оператором C, і я не бачу, наскільки цей оператор менш загальний, ніж будь-який з інших.
Барт ван Інген Шенау

1
@Giorgio: У цьому випадку все, що не відображається безпосередньо в одній інструкції по збірці, слід розглядати як синтаксичний цукор, оскільки його завжди можна розбити на більш прості фрагменти (сюди входять функції). Я не думаю, що ви не знайдете багатьох людей, які поділяють цю думку.
Барт ван Іґен Шенау

1
"Спеціальний" означає, що він використовується в особливій, обмеженій ситуації. Термін взагалі не має негативної конотації. Термін "спеціальне рішення" має негативну конотацію, оскільки зазвичай хочеться загальних рішень, а не конкретних (щоб уникнути вирішення подібних проблем знову і знову).
Джорджіо

1
Оскільки "спеціальні рішення" часто погані, може здатися, що "спеціальні" самі по собі означають погані. Але є також і «спеціальний поліморфізм» AKA функцією перевантаження ( en.wikipedia.org/wiki/Ad_hoc_polymorphism ), що непогано. Принаймні в італійській мові (моя рідна мова) використання латинського "ad hoc" само по собі не є негативним. Якщо вона має негативну конотацію англійською мовою, то пробачте про моє незнання.
Джорджіо

6

В інших відповідях не згадується ключове поняття: абстрактний синтаксис ; без цього термін "синтаксичний цукор" не має жодного сенсу.

Абстрактний синтаксис визначає елементи та структуру мов та те, як фрази цієї мови можна поєднувати для створення більших фраз. Абстрактний синтаксис не залежить від конкретного синтаксису. Термін «синтаксичний цукор», наскільки я його розумію, відноситься до конкретного синтаксису.

Загалом, розробляючи мову, вам потрібно створити конкретний синтаксис для кожного терміну вашого абстрактного синтаксису, щоб люди могли писати код вашою мовою за допомогою простого тексту.

Тепер скажімо, що ви створюєте незручний конкретний синтаксис для foo . Користувачі скаржаться, а ви реалізуєте новий конкретний синтаксис для відображення того ж абстрактного синтаксису . Результатом є те, що ваш абстрактний синтаксис та семантика не змінилися, але тепер у вас є два конкретні синтаксиси для одного і того ж абстрактного синтаксичного терміна.

Я вважаю, що люди мають на увазі, коли кажуть «синтаксичний цукор» - зміни, які впливають лише на конкретний синтаксис, але які не впливають на абстрактний синтаксис чи семантику.

І тому різниця між "синтаксичним цукром" та "конкретним синтаксисом" тепер очевидна. Для мене. :)

Це тлумачення також допомагає пояснити, що міг означати Алан Перліс, коли він сказав, що "синтаксичний цукор спричиняє рак з комою": весь конкретний синтаксичний цукор у світі не може виправити слабкий абстрактний синтаксис, і всі зусилля, які ви витрачаєте, додаючи, що цукор є зусиль, які ви не витрачаєте на вирішення реальної проблеми - абстрактного синтаксису.


Я також повинен зазначити, що це виключно моя думка; Я вірю лише тому, що це єдине тлумачення, яке я можу вважати, що має для мене сенс.


1
Я також думав про порівняння абстрактного та конкретного синтаксису, але не впевнений, що це завжди пояснює синтаксичний цукор. Наприклад, в C, заданому вказівником pна структуру, що містить поле x, виконують вирази (*p).xта p->xмають однаковий абстрактний синтаксис? Але я думаю, що було б чудово, якби все зводилося до абстрактного проти конкретного синтаксису.
Джорджіо

@ Джорджіо, на жаль, я не знаю достатньо С, щоб впевнено заявити, чи є один із них синтаксичним цукром для іншого, або як виглядатимуть їх абстрактні синтаксичні дерева. Або навіть якщо специфікація С насправді визначає абстрактний синтаксис. :(

1
Перший вираз можна проаналізувати як дерево з .коренем. Лівий підвузлик кореня - a *, а його дочірня частина - p. Правий підрозділ кореня є x. Для другого виразу дерево абстрактного синтаксису має a ->в корені, а у кореня двоє дітей pта x. Я намагаюся розібратися, чи є сенс розібратися в обох виразах по-різному, щоб у них було одне і те саме абстрактне синтаксичне дерево, але я не бачу, як зараз.
Джорджіо

3
Я не думаю, що це дерево розбору, навіть якщо його часто описують як AST, є таким же, як і абстрактний синтаксис, про який говорить Метт. Обидва вирази мають однакову дію ( перетворіть тип вказівника у тип посилання, потім отримайте посилання на учасникаx )
Марно

1
"Обидва вирази мають однакову дію (перетворять тип вказівника у тип посилання, потім отримують посилання на член x)": Це семантика, а не абстрактний синтаксис. Абстрактний синтаксис посилається на те, щоб залишати непотрібні деталі конкретного синтаксису (як-от (або ;) для створення дерева, що відображає фактичну структуру програми (див. En.wikipedia.org/wiki/Ab абстракт_syntax_tree ). Однак у абстрактному синтаксисі нічого не сказано (поки що) про семантику програми.
Джорджіо

4

Синтаксичний цукор - це підмножина синтаксису мов. Основна ідея полягає в тому, що існує більше ніж один спосіб сказати те саме.

Чому важко сказати, які шматки є синтаксичним цукром, а які - "чистим синтаксисом", - це твердження типу "важко сказати, яка форма вийшла першою" або "важко дізнатися, яким способом автор мови" чи " дещо довільно вирішувати, яка форма простіша ".

Що дозволяє легко вирішити, які твори чисті чи цукристі, - це задати питання в рамках конкретного упорядника чи перекладача. Чистий синтаксис - це те, на що компілятор перетворює безпосередньо машинний код або на який безпосередньо відповідає інтерпретатор. Цукор - це матеріал, який спочатку перетворюється на деякі інші синтаксичні речі до того, як трапляться ці прямі речі. Залежно від реалізації це може бути або не збігатися з тим, що задумав автор, або навіть тим, що заявляє мовна специфікація.

На практиці саме так вирішується реальність питання.


Ця відповідь неправильно пов'язує реалізацію синтаксису з тим, чи це цукор, чи ні. Я ніколи не бачив аргументів = про те, чи є елемент мови "цукровим" чи ні, це стосується того, як елемент реалізований. Йдеться лише про те, чи дублює він синтаксично інший, потворніший елемент.
GreenAsJade

3

Дійсно, ваша перша цитата з Вікіпедії говорить, що все "... робить речі легшими для читання ...", ".... солодше для людей для використання ....".

У письмовій формі скорочені форми, такі як "не" чи "не", можна вважати синтаксичним цукром.


Поміркуйте (1) "Я повинен іти зараз" проти (2) "Я повинен іти зараз": Чи (1) синтаксичний цукор для (2)?
Джорджіо

1
@Giorgio Я б сказав, що ні.
ozz

Через читабельність ("слід" не читабельніше, ніж "повинно") або через значення ("повинно" і "повинно мати" різні значення).
Джорджіо

@Giorgio досить чесно :)
ozz

1
Так, я бачу :) більше відчуваю кишку, я думаю, я не думаю, що в цьому прикладі можна прочитати більше, ніж інший
ozz

3

Зазвичай синтаксичний цукор - це частина мови, яка може бути виражена наявною частиною мови (синтаксисом) без втрати загальності, але з можливою втратою ясності. Іноді компілятори мають чіткий етап знежирення, який перетворює AST, створений вихідним кодом, і застосовує прості кроки для видалення вузлів, відповідних цукру.

Наприклад, у Haskell є синтаксичний цукор для монад із наступними правилами, що застосовуються рекурсивно

do { f }            ~> f
do { g; h }         ~> g >> do h
do { x <- f; h }    ~> f >>= \x -> do h
do { let x = f; h } ~> let x = f in do h

Зараз це не має значення, що це означає саме - однак ви можете бачити, що спеціальний синтаксис на LHS може бути перетворений на щось більш базове на RHS (а саме функції функцій, лямбда та lets). Цей крок дозволяє зберегти найкраще з обох світів:

  1. Синтаксис на LHS легше програмісту (синтаксичний цукор) висловлювати існуючі ідеї більш чітко
  2. Однак, оскільки підтримка компілятора для конструкцій RHS існує вже в компіляторі, не потрібно трактувати це як щось особливе поза парсером та знешкодженням (за винятком повідомлення про помилки).

Аналогічно в C можна уявити правило перезапису знезараження (через перевантаження оператора тощо. Це не вірно для C ++):

f->h ~> (*f).h
f[h] ~> *(f + h)

Можна уявити, як писати всі програми без використання ->або []на C, які сьогодні використовують цю конструкцію. Однак програмістам було б важче використовувати його, отже, надаючи синтаксичний цукор (я думаю, у 70-х це може спростити роботу і для компіляторів). Це, можливо, менш зрозуміло, оскільки ви можете технічно додати таке, абсолютно дійсне правило перезапису:

*f ~> f[0] -- * and [] have the same expressiveness 

Чи поганий синтаксичний цукор? Не обов'язково - є небезпека, що він буде використаний як вантажний культ, не розуміючи глибшого значення. Наприклад, наступні функції еквівалентні в Haskell, але багато початківців написали б першу форму, не розуміючи, що вони надмірно синтаксично використовують цукор:

f1 = do x <- doSomething
        return x
f2 = doSomething

Крім того, синтаксис цукру може переплутати мову або бути занадто вузьким, щоб дозволити узагальнений ідіоматичний код. Також це може означати, що мова недостатньо потужна, щоб робити певні речі легко - це може бути задумом (не давайте розробникам чіткі інструменти або дуже специфічну мову ніші, що додавання більш потужної конструкції зашкодить іншим цілям) або упущення - остання форма дала синтаксису цукор погану назву. Якщо мова є достатньо потужною для використання інших конструкцій без додавання синтаксичного цукру, вважати її більш елегантною використовувати.


3

Я думаю, що найбільш очевидним прикладом може бути синтаксис "+ =" у C.

i = i + 1;

і

 i +=  1;

зробіть точно те ж саме і компілюйте в точно той же набір інструкцій з машини. Друга форма зберігає пару символів набравши текст, але, що ще важливіше, це дає зрозуміти, що ви змінюєте значення на основі його поточного значення.

Я збирався навести оператор "++" пост / префікс як канонічний приклад, але зрозумів, що це більше, ніж синтаксичний цукор. Немає можливості виразити різницю між ++ i та i ++ в одному виразі за допомогою i = i + 1синтаксису.


+ = може бути корисним у таких випадках a[f(x)] += 1.
Флоріан Ф

1

Спочатку я торкнуся деяких інших відповідей на конкретному прикладі. Діапазон C ++ 11 для циклу (подібно до циклів foreach на різних інших мовах)

for (auto value : container) {
    do_something_with(value);
}

точно еквівалентний (тобто, цукровій версії)

for (auto iterator = begin(container); iterator != end(container); ++iterator) {
    do_something_with(*iterator);
}

Тепер, не дивлячись на те, що до мови не додано нового абстрактного синтаксису чи семантики, він справді корисний.

Перша версія робить наміри (відвідування кожного елемента в контейнері) явним. Він також забороняє незвичну поведінку, таку як модифікація контейнера під час обходу, або подальше просування iteratorв тілі петлі, або неповторно неправильні умови циклу. Це дозволяє уникнути можливих джерел помилок і, тим самим, зменшує труднощі з читанням і міркуванням про код.

Наприклад, помилка з одним символом у другій версії:

for (auto iterator = begin(container); iterator <= end(container); ++iterator) {
    do_something_with(*iterator);
}

дає помилку, що минула в кінці, та не визначену поведінку.

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


По-друге, до початкового питання:

Чи є реальна різниця між синтаксисом та синтаксичним цукром?

Ні, "синтаксичний цукор" - це (конкретний) синтаксис мови, який вважається "цукровим", оскільки він не розширює абстрактний синтаксис або основну функціональність мови. Мені подобається відповідь Метта Фенвіка на це.

Кому це важливо?

Для користувачів мови це важливо, як і будь-який інший синтаксис, і тому цукор надається для підтримки (і в деякому сенсі благословення) конкретних ідіом.

Нарешті, щодо питання про бонус

Позначення [] полегшує цю абстракцію.

це дуже схоже на визначення синтаксичного цукру: він підтримує (і надає благословення для авторів мови), використовуючи покажчики як масиви. p[i]Форма на самому ділі не більш обмежувальна , ніж *(p+i), тому єдине відмінністю є чіткою зв'язком наміри (і невеликий виграш читання).


По-перше, ви кажете, що "[діапазон, заснований на циклі] точно рівнозначний (тобто, цукрова версія) [якась інша річ]". Але потім ви кажете, що це інше, оскільки він забороняє змінювати контейнер під час проходу ... і є інші відмінності, які роблять це більше, ніж просто просте синтаксичне перетворення, яке ви описали (наприклад, поведінка, коли "контейнер" є тимчасовим). Ці відмінності означають, що це не просто синтаксичний цукор, правда? Тож мені здається, можливо, це не гарний приклад синтаксичного цукру.
Дон Хетч

Я не сказав, що це еквівалентно певній загальній петлі , я сказав, що це еквівалентно конкретному циклу. Конкретний цикл залишався вірним контейнер, і являє собою дуже поширену ідіому - але вам все ще потрібно уважно прочитати кожен загальний цикл , щоб сказати , є чи він після цієї загальної ідіоми, або якщо що - щось незвичайне таїться в тілі циклу. Новіший цикл - це цукор для цієї загальної ідіоми , оскільки він є менш дієслівним і чіткіше передає ідіому, що використовується. Це не так, і я ніколи не стверджував, що це було, якось цукор для загальної ідеї петлі.
Марно

0

Якою б не була первинна конотація фрази, сьогодні це насамперед пейоративна, майже завжди виражається як синтаксичний цукор «справедливий» або «тільки». Це в значній мірі важливо лише для програмістів, які люблять робити справи нечитабельно і хочуть стислий спосіб виправдати це своїм колегам. Визначення тих, хто в першу чергу вживає цей термін, з їхньої точки зору, було б таким:

Синтаксис, який є зайвим з іншими більш широко застосовуваними синтаксисами, щоб забезпечити милицю для програмістів, які насправді не розуміють мову.

Ось чому ви отримуєте два протилежних висновки для одного і того ж синтаксичного елемента. Ваш перший приклад позначення масиву - це використання оригінального позитивного значення цього терміна, щось подібне до відповіді Барта. Ваш другий приклад - захист позначення масиву проти звинувачення бути синтаксичним цукром у пейоративному сенсі. Іншими словами, аргументація синтаксису - це корисна абстракція, а не милиця.


Я думаю, пейоративне значення терміна ("це лише синтаксичний цукор") походить від того, що синтаксичний цукор не додає жодної інформації.
Джорджіо

1
Це може виходити з ідеї, що синтаксична не додає жодної інформації , але ця ідея не є фактом. Інформація про наміри (наприклад, використовувати відому ідіому) все ще є інформацією.
Марно

@Useless: За інформацією я мав на увазі, що програма поводиться так само з синтаксичним цукром або без нього. Звичайно, він може читатись із синтаксичним цукром (він додає інформацію / документацію для читача), що є перевагою.
Джорджіо

Богус. Синтаксичний цукор - це не пейоратив. Будь-який програміст, який вартує своєї солі, створить бібліотеки, які інкапсулюють та спростять складніші завдання, а не копіюють та вставляють один і той же код у всі місця. Це призводить до кращого поведінки, більш ремонтованого коду. Це, по суті, те, що синтаксичний цукор досягається шляхом абстрагування загальних, хоча і складних, моделей на простіші синтаксиси.
Крейг

Я кажу, що люди зазвичай означають цей термін як образа, я не коментую саму основну практику. Якщо сказати, що слово "ідіот" є вигідним, не означає, що всі люди - ідіоти. Коли люди хочуть говорити про практику позитивно, вони зазвичай використовують такі терміни, як "абстракція" або "інкапсуляція".
Карл Білефельдт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.