Mark Bottjer mark_bottjer at hotmail.com
Fri Aug 6 23:01:42 CEST 2004

David Fraser wrote:
> I like this idea. What about using the list syntax instead of the @
> syntax:
> [static, synchronized, types(int, int), returns(None) ]:
 >   def foo():
>     pass

<rant level="hysterical">
No, no, NO! Lists are value expressions: not statements, not 
declarators, and most certainly not suites!!!

Sorry, just had to get that out of my system... :)

Seriously, though, one problem I see is that this can get obfuscative 
really fast as the number or complexity of decorators grows:

    types(int, int),
    the( (pain, to, read, past))
     def foo():

By the time I've read all of that, I've likely forgotten what it was I 
was looking for in the first place. Of course, the @ syntax as it stands 
has the same problem, but at least it doesn't introduce spurious 
indentation in the process.

> This would then take away the argument against a valid list before a
> def being valid python but not previously having any effect...

Right. At the expense of a grammar that is nonsensical when viewed in 
the context of how those symbols work elsewhere in the language. Here we 
have a list (okay), containing a bunch of function names (okay), which 
get called via side-effect on something not explicitly indicated 
(er...), and starts a block of code (say what???).

The (){}[] symbols all already *mean* something in python (often more 
than one thing, actually). The @ doesn't mean anything yet, so it is a 
perfect candidate for a completely new concept such as this. I just 
think that they put it in the wrong spot.

> declare [static, synchronized, types(int, int), returns(None)]:
 >   def foo():
 >     pass
 >   def bar():
 >     pass

People keep suggesting this one, and I just don't see it. Yes, it's 
shorter (marginally, sometimes). But is it really clearer? I don't think 
so. Now, instead of just having to look at the preceding few lines to 
figure out what decorators are being used, you have to look up an 
arbitrary number of lines. Not fun when one's functions start getting 
real-world sized.

I understand the desire to reduce the redundancy, but even this small 
example shows a fundamental problem with this approach. In all but the 
most simple cases, most functions will end up with *different* sets of 
decorators. Case in point: both foo and bar above take (int, int) and 
return None. Such parity rarely survives in the wild. This leaves us 
with even more of a mess:

  declare [static, synchronized]:
    declare [returns(None)]:
      declare [types(int)]:
        def foo(a):
      declare [types(int, int)]:
        def bar(a, b):
    declare [returns(int)]:
      def baz():

I *shudder* to think of trying to sort this out when these functions 
contain real code.

(FYI: None of this is directed at you, personally. Your post just 
happened to be the first post I found suggesting this kind of syntax.)

   -- Mark

More information about the Python-list mailing list