remaining decorator syntax options

Bengt Richter bokr at oz.net
Wed Aug 11 02:12:44 CEST 2004


On 10 Aug 2004 12:33:36 -0700, steven.bethard at gmail.com (Steven Bethard) wrote:

>So here's the state of the decorator debate as I see it:
>
>
>*** Location
>
>GvR pretty strongly wants decorators before the function:
>
>http://mail.python.org/pipermail/python-dev/2004-August/047112.html
>http://mail.python.org/pipermail/python-dev/2004-August/047279.html
>
>The idea being that decorators and other function properties should
>not look like part of the function's code.  I don't think there's much
>chance of swaying GvR on this count.
>
>
>*** Indentation
>
>Since location has been pretty much decided, I see three options here:
>
>(1)
><indicator> dec
>def f():
>    pass
>
>(2)
><indicator>
>    dec
>def f():
>    pass
>
>(3)
><indicator> dec
>    def f():
>        pass
>
(4)
dec<indicator>
def f():
    pass

Suggested indicator: '(=' or '(:' or '(%'  e.g.,

dec(=
def f():
    pass

>GvR definitely disliked the third version because it meant that class
>functions could all be at different indentation levels.  The PEP
>suggests that the second version was disliked because it suggests that
>"using" is introducing a new scope (although arguments about if/else
>behavior seemed to counter this somewhat).  There didn't seem to be
>any arguments that made version 2 drastically better than version 1
>though, so it seems most likely that a BDFL pronouncement will give us
>version 1.
>
>
>*** List notation
>
>Assuming a pre-def, non-indented decorator, here are the remaining
>list notations:
>
>(1)
><indicator> dec1
><indicator> dec2
><indicator> dec3
>
>(2)
><indicator> [dec1, dec2, dec3]
>
>(3)
><indicator> dec1, dec2, dec3
>
(4)
dec1<indicator>
dec2<indicator>
dec3<indicator>

e.g.,

dec1(=
dec2(=
dec3(=
def f(): pass


>I believe that version 3 was vetoed because it makes it too hard to
>break lists of decorators across lines.  GvR's preference is
>definitely for 1, but that may be influenced by his decision for the
>indicator.  I have a feeling that how long the indicator is directly
>affects which of (1) or (2) is preferred.  Compare:
>
>@dec1
>@dec2
>@dec3
>
>vs.
>
>@[dec1, dec2, dec3]
>
>and
>
>using dec1
>using dec2
>using dec3
>
>vs.
>
>using [dec1, dec2, dec3]
>
>It seems like with a single symbol character, the non-list syntax is
>much more concise, and probably clearer.  However with a keyword
>syntax the list seems the better option.
>
>Which brings us, of course to the final section:
>
>*** Indicator
>
>The options seemed to be:
>
>(1) a symbol (@, |, etc.)
>(2) a keyword (using, decorate, etc.)
>(3) similar to function
>(4) no indicator
>
(5) postfixed indicators [ (: (= (% <<< etc ]
    dec1 (=
    dec2 (=
    def foo(): pass


>Options (3) and (4) were ruled out because (given that we're already
>relegated to a before-def syntax) they are already valid syntax, and
>redefining them for decorators means changing the expected semantics
>of the statements.
>
>Option (1), with @, is GvR's favorite, and does have something of a
>Java backing.  It has the substantial disadvantage that there is no
>particular reason (or even some sort of mnemonic) for which @ (or |
>for that matter) should mean "decorator".
>
>With option (2), we can choose a keyword that does suggest a
>decorator.  Even "using", which is not an outstanding choice, is at
>least more intuitive than '@'.  Option (2) does have the disadvantage
>that it requires introducing a new keyword, but this is not
>insurmountable -- it was done before for generators.  And GvR even
>said that he would consider this option if there enough support for
>it.
>
>----
>
>So here's my suggestions:
>
>Let's leave the location and indentation arguments behind.  We're not
>making much progress on them, and I don't think there's much chance of
>swaying GvR.  Reiterating all the old arguments won't get us closer to
>a syntax we're happy with.
>
>I think once the indicator argument is decided, the list-structure
>decision will fall out of it.
>
>So I'd suggest that we put all our effort into the indicator
>discussions.  If you have a good argument for why a keyword is better
>than a symbol, or why a symbol is better than a keyword, please voice
>them now.  And remember that 'because it's prettier' or 'because it's
>uglier' are not aguments GvR will consider.  We need strong arguments,
>that argue on the basis of readability or learnability or
>maintainability, etc.
You don't think GvR goes for prettier, other things being equal?

>
>
>... and my opinion:
>
>A keyword is much more Pythonic than a symbol:
Yes, except that what we have is really nested function calls,
passing a special argument, so maybe the decorating functions
ought to look like they are being invoked as functions. I.e.,

    deco1(
    deco2(
    arg_that_happens_to_be_created_by_a_def_statement_and_suite
    ))

But, since it's not an ordinary argument list, we need an alternative
to the function-calling expression trailer (...) that yet suggests calling.
Since the def defines its own end, we don't need the )) above, but we do
need a different '(' -- so I'm suggesting (= or maybe (: or (% or <<<, so
the above simply becomes

    deco1(=
    deco2(=
    arg_that_happens_to_be_created_by_a_def_statement_and_suite

and deco1 and deco2 can just be arbitrary expressions evaluating to something
callable.

If other statement:suite blocks can be interpreted as defining arguments useful
to pass to a function, then
    func(=
    statement: suite
could be used in a generalized way to operate on those. The loose end here is
re/binding the function (or class, etc) name. I.e., would you want to write

    foo = deco1(=
    deco2(=
    def foo():
        pass
?
Or maybe

    foo = (
    deco1(=
    deco2(=
    def foo():
        pass
    )

So long as postfixed (= is just sugar for the current use case,
it doesn't matter, of course. The rebinding can be a side effect
of an expression whose value is discarded.


>
>A well chosen keyword can suggest the meaning of the construction,
>e.g. "using ... def ..." suggests that the decorators are used as part
>of the definition of the function.  A symbol like '@' or '|' cannot
>easily suggest the meaning in this manner.
But deco(...) suggests calling deco with something, and that's what's happening.
We just need to distinguish the def-result-as-argument variant, IMO.
>
>For this reason, a keyword makes both reading and learning Python
>decorator syntax easier.  If you encounter "using ... def ..." and
>have to guess at it's meaning, your knowledge of English "using" can
>now be applied to guess the meaning of Python "using".  This is not
>true of a symbol like '@' or '|'.
see above ;-)
>
>(An additional argument might be that it will be at least /possible/
>to Google "using", but impossible to do so for "@" or "|".  This was
>one of the frustrating things about Perl for me -- if I didn't know
>what a symbol did, I couldn't Google it because it wasn't a word. 
>Remember that if you don't know it's a decorator, you don't know to
>search for "decorate" ;)
I do like google. How about a postfixed keyword indicator like 'munges' ;-)

deco1 munges
deco2 munges
def foo(): pass

;-)
>
>
>hoping-to-keep-this-dicussion-productive-ly-yrs,
>
hoping-to-have-added-something-useful-ly-yrs,

Regards,
Bengt Richter



More information about the Python-list mailing list