<p>Many languages have large amounts of syntactic sugar. For example, while working with Python there are seemingly many ways to express the same operations.</p>
<p>For example, in list comprehension</p>
<pre><code>[x for x in range(10)]
</code></pre>
<p>can be used rather than</p>
<pre><code>li = []
for i in range(10):
    li.append(i)
</code></pre>
<p>I was going through the <a href="https://docs.python.org/3/reference/grammar.html" rel="noreferrer">Python Full Grammar Specification</a> and it just seemed so long and unwieldy. The Zen of Python itself mentions that &quot;Readability counts.&quot; and &quot;There should be one-- and preferably only one --obvious way to do it.&quot; This is seemingly violated with multiple syntaxes for 1 operation.</p>
<p>I know that languages tend to accumulate bloat and sugar over time, but what are the exact reasons for which this sugar should be considered and subsequently introduced.</p>

<syntax><language-design><syntactic-sugar>
What are the advantages of syntactic sugar and when should it be added?
CC BY-SA 4.0
2023-05-19T17:40:18.583Z
I don't think list comprehensions are syntactic sugar of a for loop and `append`, it's more like syntactic sugar of `map` and `lambda`.
naffetS
CC BY-SA 4.0
2023-05-17T05:26:25.493Z
If the sugar can do something unique, that cannot be done otherwise. For example `x += 1` is the **only way** to add 1 to `x` without evaluating `x` more than once. (Besides `x -= -1;`)
CPlus
<p>Syntactic sugar is a violation of <a href="https://en.wikipedia.org/wiki/Orthogonality_(programming)" rel="nofollow noreferrer">orthogonality</a>, so it should be used sparingly. It's most useful when:</p>
<ol>
<li>It can be applied to a variety of scenarios (e.g., not just &quot;cryptographers writing bit-flipping functions&quot;, unless that's your language niche).</li>
<li>It comes up often.</li>
<li>Its representation hints at its meaning.</li>
<li>The alternative way of writing it is:
<ul>
<li>surprisingly verbose,</li>
<li>requires making unimportant decisions,</li>
<li>or makes the source code ugly (adding indentation levels, line noise, etc).</li>
</ul>
</li>
</ol>
<p>To take the Python list comprehension example, in a more complete context:</p>
<pre class="lang-python prettyprint-override"><code>send_email([u.email for u in users if u.is_active])
</code></pre>
<p>vs</p>
<pre class="lang-python prettyprint-override"><code>active_users = []
for user in users:
    if user.is_active
        active_useres.append(user.email)
send_email(active_users)
</code></pre>
<ol>
<li>Applicable to multiple scenarios? Definitely.</li>
<li>Comes up often? Yep.</li>
<li>Clear meaning? I'd say so.</li>
<li>Is the alternative undesirable? Yes on verbosity and unimportant decisions. The comprehension is an expression, and hence can be done inline; while the for-loop is four statements. And we had to pick a name for the temporary variable, which is famously hard (it should probably be <code>active_users_emails</code> instead).</li>
</ol>
<p>And stretching the definition of syntactic sugar a bit, Rust's <a href="https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator" rel="nofollow noreferrer"><code>?</code> operator</a> is also a good example.</p>
<p>On the side of bad examples, I'd vote for Bash's variable expansions:</p>
<pre class="lang-bash prettyprint-override"><code>$var
${var}
&quot;$var&quot;
&quot;${var}&quot;
</code></pre>
<p>Out of the four, only the last one does (mostly) what people want 99% of the time, and it's the ugliest. The quotes change the behavior of the expansion in non-obvious ways, and all of them have severe shortcomings, like expanding to empty strings when undefined.</p>

CC BY-SA 4.0
2023-06-30T13:14:14.970Z
2023-06-30T13:14:14.970Z
BoppreH
CC BY-SA 4.0
2024-01-25T21:40:27.333Z
FWIW, Rust's `?` operator can be exactly implemented as syntax sugar: `expr?` is equivalent to `match expr { Ok(x) => x, Err(e) => return Err(e.into()) }`. So this isn't stretching the definition, I don't think.
kaya3
CC BY-SA 4.0
2024-11-02T02:10:12.687Z
In terms of what the Bash (Shell) snippets *do*, the braces make no difference whatsoever, except to disambiguate based on the following context; so `"$var"foo` and `"${var}"foo` behave absolutely identically. While `$varfoo` and `${var}foo` differ, they should generally be avoided anyway.
Martin Kealey
<p>I wouldn't call the given example &quot;sugar&quot;.
The comprehension tells the interpreter <em>what</em> result you want, while the for-loop tells the interpreter <em>how</em> to generate that result.</p>
<p>The results might be the same, but the comprehension gives the interpreter far more latitude in how it does it.
In a more complicated example, the comprehension could be far more efficient than a loop.</p>
<p>There really is &quot;<em>only one obvious way to do it</em>&quot;; for anyone fluent in the language the loop would <em>not</em> be an obvious way of doing it.</p>
<p>It's similar to:</p>
<pre><code>n1 = x * 4;
n2 = x + x + x + x;
</code></pre>
<p>where the first is <em>what</em> you want, and the second specifies <em>how</em> to calculate it.
The addition method generates the same result, but it is not an obvious way of doing this calculation.</p>
<p>The interpreter might even calculate <code>n1</code> as <code>x&lt;&lt;2</code>. which is faster than a multiplication.</p>
<hr />
<p>In C, a good example of sugar is strings.</p>
<pre><code>auto char s1[] = &quot;sugar&quot;;
auto char s2[] = { 's', 'u', 'g', 'a', 'r', '\0' };
</code></pre>
<p><code>s1</code> and <code>s2</code> are identical objects (arrays of characters of length 6) with identical values.</p>
<p>Using the quotation syntax makes it a lot easier to write and read the code. Even though it means exactly the same thing to the compiler, this unnecessary syntax is provided to make life easier for the humans.
Except for in unusual circumstances, the quotation syntax is the one obvious way that everyone will use.</p>
<p>Consider something like:</p>
<pre><code>r1 = f(a1, a2, a3);
r1 = call f with a1, a2, and a3;
</code></pre>
<p>Anyone fluent in the language would see no significant benefit to introducing the second syntax, and would never use it.
It is totally unnecessary.</p>

CC BY-SA 4.0
2023-05-20T03:31:36.927Z
2023-05-20T03:31:36.927Z
Ray Butterworth
CC BY-SA 4.0
2023-05-20T05:15:39.073Z
*"the for-loop tells the interpreter how to generate that result."* ─ this is sort of true, but a language implementation is generally free to transform programs however it likes, so long as the observable behaviour is the same. For example, the loop `x = 0; for i in range(10000): x += i;` could very well be replaced with the statement `x = 49995000`. An interpreter which does that would not be breaking any rules, but it also wouldn't be executing the `for` loop the way the code told it to.
kaya3
CC BY-SA 4.0
2023-06-30T14:52:26.770Z
The C example isn't quite sugar. While they may both work for `char s[]`, only the string literal works for `const char *s`.
Bbrk24
CC BY-SA 4.0
2023-06-30T23:53:42.760Z
@Bbrk24 In some cases you can use a compound literal with `char *s`, but there are lifetime considerations.
Barmar
CC BY-SA 4.0
2024-05-31T22:42:43.547Z
@Barmar: Compound literals in C99 are syntactic salt (something that looks like sugar, but is generally inferior to the replaced construct) for named objects whose lifetime are unambiguously determined by location and storage class.
supercat
CC BY-SA 4.0
2024-11-02T02:17:03.507Z
@Bbrk24 the sugaring effect of C-string quotes differs depending on context. When initialising a `char` array, it's as given in the answer; when used elsewhere it's closer to `(static const char[]){'h','e','l','l','o',0}` (except that that's currently illegal - we cannot  use storage specifiers like `static` on anonymous objects created by compound literals).
Martin Kealey
CC BY-SA 4.0
2024-11-02T02:20:02.607Z
@ray-butterworth: your last example is giving my COBOL flashbacks. Aargh, please no.
Martin Kealey
CC BY-SA 4.0
2024-11-02T02:22:22.090Z
@MartinKealey, I still miss "ADD CORRESPONDING".
Ray Butterworth
CC BY-SA 4.0
2023-08-04T10:03:12.517Z
@kaya3-supportthestrike Python is a tricky example, since `x += i` is sugar for `x.__iadd__(i)`
Warbo
<p>Syntax sugar means language constructs which are (or can be) implemented in terms of other language constructs, rather than directly in the host language. Syntax sugar serves at least three purposes:</p>
<ol>
<li>It reduces the complexity of the backend by implementing more language features in the frontend.</li>
<li>It adds expressiveness to the language for relatively little implementation effort,</li>
<li>It removes some of the need for excessive boilerplate code and inscrutable idioms.</li>
</ol>
<hr />
<p>On the implementation complexity: the backend of a compiler is typically the most cognitively complex part, since it does the necessary checks and analyses for program correctness, and also has to transform the program from one format (the AST) to another (the IR, bytecode, or other target language) while preserving the program's meaning. Each analysis or pass the backend does, you will typically have to walk the AST and do something for each node. So the fewer different kinds of node, the easier the backend will be to write.</p>
<p>Because syntax sugar can be implemented in the frontend (by desugaring), it allows language constructs to be added to the grammar without adding more kinds of nodes to the AST. For example, if you already have assignment expressions and a &quot;<a href="https://languagedesign.stackexchange.com/q/79/89">comma operator</a>&quot;, then you can implement <code>let</code>-<code>in</code> expressions by transforming <code>let A = B in C</code> into <code>(A=B, C)</code> in the frontend, and then there is no need for a distinct <code>LetIn</code> node in the AST. Or if you already have lambda expressions then you can implement <code>let</code>-<code>in</code> as <code>(lambda A: C)(B)</code>.</p>
<hr />
<p>On expressiveness, of course the list comprehension and the <code>for</code> loop in your example achieve the same result, but the list comprehension is clearly preferable for most programmers: it is one line instead of three, and it can be used in place of an expression where the <code>for</code> loop must be a statement. So you can write a list comprehension directly as a function's argument, or the body of a <code>lambda</code>.</p>
<p>Yes, this means there is more than one way to write the same thing, but there is one &quot;obvious&quot; way to write it; the other way is &quot;obviously&quot; inferior. In general, syntax sugar <em>always</em> means there is an alternative way of writing it, i.e. the syntax that it's &quot;sugar&quot; for, also known as the &quot;desugared&quot; form. But when the sugar is significantly neater or more convenient, it has clear benefits, and the cost is relatively low since it can be implemented by transforming the AST into the desugared form, rather than adding more code generation logic to the backend.</p>
<p><sub>I should note that Python's list comprehensions aren't exactly syntax sugar; they aren't implemented by transforming the AST, and they don't behave exactly like a standard <code>for</code> loop in some regards. For one, they are executed in a separate stack frame.</sub></p>
<hr />
<p>On boilerplate and idioms, once a language becomes more widely used, these will start showing up. To define terms, &quot;boilerplate&quot; means a standard form of code that must be written very similarly each time to do a menial task, and an &quot;idiom&quot; is the use of a language construct for something other than its main purpose. It's not necessarily obvious when initially designing the language what boilerplate and idioms you're encouraging, but over time you'll start to see certain ways that the language can be used to solve certain problems, repeated over and over.</p>
<p>So a good time to add syntax sugar to a language is after you have some experience with using the language yourself, or seeing other people's use of the language. By observing what the boring or obtuse parts about using your language are, you can find out what tasks need more concise or clearer syntax. If your project is open source or you have a public issue tracker, requests for syntax sugar may also come in directly from users, and these may be some of the best effort-to-reward improvements you make to your language.</p>

CC BY-SA 4.0
2023-05-17T06:39:35.400Z
2023-05-17T06:39:35.400Z
kaya3
CC BY-SA 4.0
2023-06-30T12:41:02.007Z
I'm not completely sold on having syntax sugar converted before the AST is built. It's going to mess up with code formatters/pretty printers, and error message may refer to AST node types that are not actually present ("error in the tuple at line 3? But there's no tuple there!").
BoppreH
CC BY-SA 4.0
2023-06-30T13:25:07.047Z
@BoppreH Code formatters and pretty printers don't use the AST, because the AST has already lost information ─ particularly comments and intentional line breaks/spacing in the source code, potentially also the order of things which might be represented in a dictionary or bitfield. So these tools generally work with a different representation, like a concrete syntax tree (CST). Regarding error messages, this usually isn't a problem in practice because any synthetic AST nodes you create generally aren't the source of errors, but if you do get misleading error messages because of this then ...
kaya3
CC BY-SA 4.0
2023-06-30T13:25:20.653Z
... there are ways to address it, but perhaps you should ask it as a separate question.
kaya3
# What are the advantages of syntactic sugar and when should it be added?
Posted by: username_0 on 2023-05-17
Many languages have large amounts of syntactic sugar. For example, while working with Python there are seemingly many ways to express the same operations.
For example, in list comprehension
[x for x in range(10)]

can be used rather than
li = []
for i in range(10):
    li.append(i)

I was going through the Python Full Grammar Specification and it just seemed so long and unwieldy. The Zen of Python itself mentions that "Readability counts." and "There should be one-- and preferably only one --obvious way to do it." This is seemingly violated with multiple syntaxes for 1 operation.
I know that languages tend to accumulate bloat and sugar over time, but what are the exact reasons for which this sugar should be considered and subsequently introduced.
**Tags:** syntax language-design syntactic-sugar
> **Comments:**
> **username_2**: If the sugar can do something unique, that cannot be done otherwise. For example `x += 1` is the **only way** to add 1 to `x` without evaluating `x` more than once. (Besides `x -= -1;`)  
> **username_1**: I don't think list comprehensions are syntactic sugar of a for loop and `append`, it's more like syntactic sugar of `map` and `lambda`.  
---
## 3 answers
### Answer by username_4 on 2023-05-17. Score: 12 | Accepted answer
Syntax sugar means language constructs which are (or can be) implemented in terms of other language constructs, rather than directly in the host language. Syntax sugar serves at least three purposes:

1. It reduces the complexity of the backend by implementing more language features in the frontend.
2. It adds expressiveness to the language for relatively little implementation effort,
3. It removes some of the need for excessive boilerplate code and inscrutable idioms.

---

On the implementation complexity: the backend of a compiler is typically the most cognitively complex part, since it does the necessary checks and analyses for program correctness, and also has to transform the program from one format (the AST) to another (the IR, bytecode, or other target language) while preserving the program's meaning. Each analysis or pass the backend does, you will typically have to walk the AST and do something for each node. So the fewer different kinds of node, the easier the backend will be to write.

Because syntax sugar can be implemented in the frontend (by desugaring), it allows language constructs to be added to the grammar without adding more kinds of nodes to the AST. For example, if you already have assignment expressions and a "[comma operator](https://languagedesign.stackexchange.com/q/79/89)", then you can implement `let`-`in` expressions by transforming `let A = B in C` into `(A=B, C)` in the frontend, and then there is no need for a distinct `LetIn` node in the AST. Or if you already have lambda expressions then you can implement `let`-`in` as `(lambda A: C)(B)`.

---

On expressiveness, of course the list comprehension and the `for` loop in your example achieve the same result, but the list comprehension is clearly preferable for most programmers: it is one line instead of three, and it can be used in place of an expression where the `for` loop must be a statement. So you can write a list comprehension directly as a function's argument, or the body of a `lambda`.

Yes, this means there is more than one way to write the same thing, but there is one "obvious" way to write it; the other way is "obviously" inferior. In general, syntax sugar *always* means there is an alternative way of writing it, i.e. the syntax that it's "sugar" for, also known as the "desugared" form. But when the sugar is significantly neater or more convenient, it has clear benefits, and the cost is relatively low since it can be implemented by transforming the AST into the desugared form, rather than adding more code generation logic to the backend.

I should note that Python's list comprehensions aren't exactly syntax sugar; they aren't implemented by transforming the AST, and they don't behave exactly like a standard `for` loop in some regards. For one, they are executed in a separate stack frame.

---

On boilerplate and idioms, once a language becomes more widely used, these will start showing up. To define terms, "boilerplate" means a standard form of code that must be written very similarly each time to do a menial task, and an "idiom" is the use of a language construct for something other than its main purpose. It's not necessarily obvious when initially designing the language what boilerplate and idioms you're encouraging, but over time you'll start to see certain ways that the language can be used to solve certain problems, repeated over and over.

So a good time to add syntax sugar to a language is after you have some experience with using the language yourself, or seeing other people's use of the language. By observing what the boring or obtuse parts about using your language are, you can find out what tasks need more concise or clearer syntax. If your project is open source or you have a public issue tracker, requests for syntax sugar may also come in directly from users, and these may be some of the best effort-to-reward improvements you make to your language.
> **Comments:**
> **username_3** (2023-06-30): I'm not completely sold on having syntax sugar converted before the AST is built. It's going to mess up with code formatters/pretty printers, and error message may refer to AST node types that are not actually present ("error in the tuple at line 3? But there's no tuple there!").  
> **username_4** (2023-06-30): @BoppreH Code formatters and pretty printers don't use the AST, because the AST has already lost information ─ particularly comments and intentional line breaks/spacing in the source code, potentially also the order of things which might be represented in a dictionary or bitfield. So these tools generally work with a different representation, like a concrete syntax tree (CST). Regarding error messages, this usually isn't a problem in practice because any synthetic AST nodes you create generally aren't the source of errors, but if you do get misleading error messages because of this then ...  
> **username_4** (2023-06-30): ... there are ways to address it, but perhaps you should ask it as a separate question.  
---
### Answer by username_3 on 2023-06-30. Score: 3
Syntactic sugar is a violation of orthogonality, so it should be used sparingly. It's most useful when:

It can be applied to a variety of scenarios (e.g., not just "cryptographers writing bit-flipping functions", unless that's your language niche).
It comes up often.
Its representation hints at its meaning.
The alternative way of writing it is:

surprisingly verbose,
requires making unimportant decisions,
or makes the source code ugly (adding indentation levels, line noise, etc).



To take the Python list comprehension example, in a more complete context:
send_email([u.email for u in users if u.is_active])

vs
active_users = []
for user in users:
    if user.is_active
        active_useres.append(user.email)
send_email(active_users)


Applicable to multiple scenarios? Definitely.
Comes up often? Yep.
Clear meaning? I'd say so.
Is the alternative undesirable? Yes on verbosity and unimportant decisions. The comprehension is an expression, and hence can be done inline; while the for-loop is four statements. And we had to pick a name for the temporary variable, which is famously hard (it should probably be active_users_emails instead).

And stretching the definition of syntactic sugar a bit, Rust's ? operator is also a good example.
On the side of bad examples, I'd vote for Bash's variable expansions:
$var
${var}
"$var"
"${var}"

Out of the four, only the last one does (mostly) what people want 99% of the time, and it's the ugliest. The quotes change the behavior of the expansion in non-obvious ways, and all of them have severe shortcomings, like expanding to empty strings when undefined.
> **Comments:**
> **username_4** (2024-01-25): FWIW, Rust's `?` operator can be exactly implemented as syntax sugar: `expr?` is equivalent to `match expr { Ok(x) => x, Err(e) => return Err(e.into()) }`. So this isn't stretching the definition, I don't think.  
> **username_5** (2024-11-02): In terms of what the Bash (Shell) snippets *do*, the braces make no difference whatsoever, except to disambiguate based on the following context; so `"$var"foo` and `"${var}"foo` behave absolutely identically. While `$varfoo` and `${var}foo` differ, they should generally be avoided anyway.  
---
### Answer by username_6 on 2023-05-20. Score: 2
I wouldn't call the given example "sugar".
The comprehension tells the interpreter what result you want, while the for-loop tells the interpreter how to generate that result.
The results might be the same, but the comprehension gives the interpreter far more latitude in how it does it.
In a more complicated example, the comprehension could be far more efficient than a loop.
There really is "only one obvious way to do it"; for anyone fluent in the language the loop would not be an obvious way of doing it.
It's similar to:
n1 = x * 4;
n2 = x + x + x + x;

where the first is what you want, and the second specifies how to calculate it.
The addition method generates the same result, but it is not an obvious way of doing this calculation.
The interpreter might even calculate n1 as x<<2. which is faster than a multiplication.

In C, a good example of sugar is strings.
auto char s1[] = "sugar";
auto char s2[] = { 's', 'u', 'g', 'a', 'r', '\0' };

s1 and s2 are identical objects (arrays of characters of length 6) with identical values.
Using the quotation syntax makes it a lot easier to write and read the code. Even though it means exactly the same thing to the compiler, this unnecessary syntax is provided to make life easier for the humans.
Except for in unusual circumstances, the quotation syntax is the one obvious way that everyone will use.
Consider something like:
r1 = f(a1, a2, a3);
r1 = call f with a1, a2, and a3;

Anyone fluent in the language would see no significant benefit to introducing the second syntax, and would never use it.
It is totally unnecessary.
> **Comments:**
> **username_4** (2023-05-20): *"the for-loop tells the interpreter how to generate that result."* ─ this is sort of true, but a language implementation is generally free to transform programs however it likes, so long as the observable behaviour is the same. For example, the loop `x = 0; for i in range(10000): x += i;` could very well be replaced with the statement `x = 49995000`. An interpreter which does that would not be breaking any rules, but it also wouldn't be executing the `for` loop the way the code told it to.  
> **username_7** (2023-06-30): The C example isn't quite sugar. While they may both work for `char s[]`, only the string literal works for `const char *s`.  
> **username_8** (2023-06-30): @Bbrk24 In some cases you can use a compound literal with `char *s`, but there are lifetime considerations.  
> **username_10** (2023-08-04): @kaya3-supportthestrike Python is a tricky example, since `x += i` is sugar for `x.__iadd__(i)`  
> **username_9** (2024-05-31): @Barmar: Compound literals in C99 are syntactic salt (something that looks like sugar, but is generally inferior to the replaced construct) for named objects whose lifetime are unambiguously determined by location and storage class.  
> **username_5** (2024-11-02): @Bbrk24 the sugaring effect of C-string quotes differs depending on context. When initialising a `char` array, it's as given in the answer; when used elsewhere it's closer to `(static const char[]){'h','e','l','l','o',0}` (except that that's currently illegal - we cannot  use storage specifiers like `static` on anonymous objects created by compound literals).  
> **username_5** (2024-11-02): @ray-butterworth: your last example is giving my COBOL flashbacks. Aargh, please no.  
> **username_6** (2024-11-02): @MartinKealey, I still miss "ADD CORRESPONDING".  
---
