<p>Some languages have syntactic sugar for decorators (like Python), but some languages do not (like Go).</p>
<p>PSL Some languages do not have decorators at all.</p>
<p><strong>So, what are pros and cons of syntactic sugar for decorators?</strong></p>

<syntax><syntactic-sugar><decorators>
What are pros and cons of adding special syntactic sugar for decorators?
CC BY-SA 4.0
2023-07-22T08:40:23.753Z
[Related](https://langdev.stackexchange.com/q/685/13)
The Thonnu
CC BY-SA 4.0
2023-07-22T16:51:38.000Z
I think this question would be improved by defining what does and does not count as a “decorator”. Are Java annotations decorators? Or is this really just about the Python feature, specifically?
Alexis King
CC BY-SA 4.0
2023-07-22T18:20:25.737Z
In particular, how is it a "decorator" if it *doesn't* have a dedicated syntax?
Karl Knechtel
<h2>Con: Magic</h2>
<p>Decorators are used rarely enough that many programmers don't understand what they do and how they work.</p>
<p>If your language supports multiline function expressions that might work just fine for readability</p>
<pre><code>const function = decorator(fn()=&gt;{

})
</code></pre>
<p>Vs</p>
<pre><code>@decorator
fn function() {

}
</code></pre>
<p>There is a difference in readability but it's not that much. Using a syntax people are already familiar with has a lot of benefits though.</p>
<h2>Con: Passing Arguments to decorators</h2>
<p>Decorators take the function as their only argument, so if you want parameters it gets complex. You can use currying to create a function that then returns a decorator of course, but:</p>
<ul>
<li>This means you need at least 3 levels of nested functions to construct your decorator. Depending on how verbose your function creation syntax is that may be not a big deal but for python it's very verbose</li>
<li>Users need to keep track of which decorators need parenthesis and which do not. There is no consistency. Decorators that only take optional arguments still need parenthesis</li>
</ul>
<p>In python you often need something like this:</p>
<pre class="lang-py prettyprint-override"><code>def decorator_factory(decorator_params):
    def decorator(function):
        @functools.wraps(function)
        def _inner(*args, **kwargs):
            # Do something useful
            return function(*args, **kwargs)
        return _inner
    return decorator
</code></pre>
<p>Quite verbose and hard to read. Also you need to name every level of inner function.</p>
<p>You can use type magic to allow both direct application and with arguments but it gets even more verbose to construct:</p>
<pre class="lang-py prettyprint-override"><code>def decorator_or_decorator_factory(function=None, /, *, decorator_arguments):
    def decorator(function):
        @functools.wraps(function)
        def _inner(*args, **kwargs):
            # Do something useful
            return function(*args, **kwargs)
        return _inner
     if function is not None:
         return decorator(function)
     else:
         return decorator
</code></pre>
<p>These decorators don't even do anything, yet they are already 7 and 9 lines long, just so they work well in the syntax.</p>
<p>On the other hand, if we used normal function call we could just do:</p>
<pre class="lang-js prettyprint-override"><code>function decorator({}: options, funk) {
    function inner() {
        funk(arguments);
    }
    return inner;
}
</code></pre>
<p>Still long but a lot more readable than the version adapted to make work with the decorator syntax.</p>

CC BY-SA 4.0
2023-07-22T10:28:48.537Z
2023-07-22T10:28:48.537Z
mousetail 'he-him'
CC BY-SA 4.0
2023-07-22T12:49:04.177Z
I feel like this is more the fault of the particular syntax Python went with. In Swift, `@Foo var thing = 1` creates `private var _thing = Foo(wrappedValue: 1)`, while `@Foo(other: 2) var thing = 1` creates `private var _thing = Foo(wrappedValue: 1, other: 2)`.
Bbrk24
<h2>Pro: The core function or object keeps the name</h2>
<p>In languages without decorators, you are supposed to wrap a function to the function, object or anything else to be decorated, and only assign the result to a name if it has a name. The thing to be decorated will become anonymous. It may require much more abstract and strange features than decorators to allow a function to pass the names back to its parameter.</p>
<p>It may not change anything in simple projects, but in very complicated projects, sometimes features such as reflection and profiling are frequently used, and they will depend on the names. Sometimes it's not the programmer using them, but the programmer uses a framework that is implemented on top of them.</p>
<h2>Con: It's a special case</h2>
<p>If it's just implemented as a special case, it's usually less well thought. For example, it's often restricted in wrapper functions, and you can't use members as usual in OOP, or operators. The Python examples in mousetail's answer would be simplified if you could use <code>@return</code> as a decorator.</p>
<p>Even if there are pros, it might be better to allow just using traditional function calls, and only use the decorator syntax as a modifier, so the versions not using wrapper functions could also be invented shortly.</p>
<h2>Con: Wrappers misused as attributes</h2>
<p>In some languages, decorators are frequently used to change an attribute, which is better implemented just as an attribute, instead of a wrapper. By frequently using wrappers for attributes, new programmers may have some assumptions such as the order doesn't matter, which is wrong in reality.</p>

CC BY-SA 4.0
2023-07-22T12:08:46.537Z
2023-07-22T12:08:46.537Z
user23013
CC BY-SA 4.0
2023-07-22T16:50:39.143Z
This seems sort of vague, and many of these seem like they would be specific to a particular *implementation* of decorators rather than decorators in general, conceptually speaking.
Alexis King
<h2>PRO: readability.</h2>
<p>Syntactic sugar for decorators reads better then without it.</p>
<p>With sugar:</p>
<pre class="lang-python prettyprint-override"><code>@decorator
def fn():
    ...
</code></pre>
<p>And without it:</p>
<pre class="lang-python prettyprint-override"><code>def fn():
    ...

fn = decorator(fn)
</code></pre>

CC BY-SA 4.0
2023-07-22T08:23:26.020Z
2023-07-22T08:23:26.020Z
чистов_n
CC BY-SA 4.0
2023-07-22T16:48:51.937Z
This seems essentially subjective.
Alexis King
# What are pros and cons of adding special syntactic sugar for decorators?
Posted by: username_0 on 2023-07-22
Some languages have syntactic sugar for decorators (like Python), but some languages do not (like Go).

PSL Some languages do not have decorators at all.

**So, what are pros and cons of syntactic sugar for decorators?**
**Tags:** syntax syntactic-sugar decorators
> **Comments:**
> **username_1**: [Related](https://langdev.stackexchange.com/q/685/13)  
> **username_2**: I think this question would be improved by defining what does and does not count as a “decorator”. Are Java annotations decorators? Or is this really just about the Python feature, specifically?  
> **username_3**: In particular, how is it a "decorator" if it *doesn't* have a dedicated syntax?  
---
## 3 answers
### Answer by username_4 on 2023-07-22. Score: 2
Con: Magic
Decorators are used rarely enough that many programmers don't understand what they do and how they work.
If your language supports multiline function expressions that might work just fine for readability
const function = decorator(fn()=>{

})

Vs
@decorator
fn function() {

}

There is a difference in readability but it's not that much. Using a syntax people are already familiar with has a lot of benefits though.
Con: Passing Arguments to decorators
Decorators take the function as their only argument, so if you want parameters it gets complex. You can use currying to create a function that then returns a decorator of course, but:

This means you need at least 3 levels of nested functions to construct your decorator. Depending on how verbose your function creation syntax is that may be not a big deal but for python it's very verbose
Users need to keep track of which decorators need parenthesis and which do not. There is no consistency. Decorators that only take optional arguments still need parenthesis

In python you often need something like this:
def decorator_factory(decorator_params):
    def decorator(function):
        @functools.wraps(function)
        def _inner(*args, **kwargs):
            # Do something useful
            return function(*args, **kwargs)
        return _inner
    return decorator

Quite verbose and hard to read. Also you need to name every level of inner function.
You can use type magic to allow both direct application and with arguments but it gets even more verbose to construct:
def decorator_or_decorator_factory(function=None, /, *, decorator_arguments):
    def decorator(function):
        @functools.wraps(function)
        def _inner(*args, **kwargs):
            # Do something useful
            return function(*args, **kwargs)
        return _inner
     if function is not None:
         return decorator(function)
     else:
         return decorator

These decorators don't even do anything, yet they are already 7 and 9 lines long, just so they work well in the syntax.
On the other hand, if we used normal function call we could just do:
function decorator({}: options, funk) {
    function inner() {
        funk(arguments);
    }
    return inner;
}

Still long but a lot more readable than the version adapted to make work with the decorator syntax.
> **Comments:**
> **username_5** (2023-07-22): I feel like this is more the fault of the particular syntax Python went with. In Swift, `@Foo var thing = 1` creates `private var _thing = Foo(wrappedValue: 1)`, while `@Foo(other: 2) var thing = 1` creates `private var _thing = Foo(wrappedValue: 1, other: 2)`.  
---
### Answer by username_6 on 2023-07-22. Score: 0
## Pro: The core function or object keeps the name

In languages without decorators, you are supposed to wrap a function to the function, object or anything else to be decorated, and only assign the result to a name if it has a name. The thing to be decorated will become anonymous. It may require much more abstract and strange features than decorators to allow a function to pass the names back to its parameter.

It may not change anything in simple projects, but in very complicated projects, sometimes features such as reflection and profiling are frequently used, and they will depend on the names. Sometimes it's not the programmer using them, but the programmer uses a framework that is implemented on top of them.

## Con: It's a special case

If it's just implemented as a special case, it's usually less well thought. For example, it's often restricted in wrapper functions, and you can't use members as usual in OOP, or operators. The Python examples in mousetail's answer would be simplified if you could use `@return` as a decorator.

Even if there are pros, it might be better to allow just using traditional function calls, and only use the decorator syntax as a modifier, so the versions not using wrapper functions could also be invented shortly.

## Con: Wrappers misused as attributes

In some languages, decorators are frequently used to change an attribute, which is better implemented just as an attribute, instead of a wrapper. By frequently using wrappers for attributes, new programmers may have some assumptions such as the order doesn't matter, which is wrong in reality.
> **Comments:**
> **username_2** (2023-07-22): This seems sort of vague, and many of these seem like they would be specific to a particular *implementation* of decorators rather than decorators in general, conceptually speaking.  
---
### Answer by username_0 on 2023-07-22. Score: 0
PRO: readability.
Syntactic sugar for decorators reads better then without it.
With sugar:
@decorator
def fn():
    ...

And without it:
def fn():
    ...

fn = decorator(fn)
> **Comments:**
> **username_2** (2023-07-22): This seems essentially subjective.  
---
