Maybe, just maybe @decorator syntax is ok after all

Discussion in 'Python' started by Ville Vainio, Aug 7, 2004.

  1. Ville Vainio

    Ville Vainio Guest

    It might just be that @decorator might not be all that bad. When you
    look at code that uses it it's not that ugly after all.

    A lot of the furor about this is probably because it happened so
    quicly. The situation might have been different if we had seen a
    pronouncement a week before, in the vein of "I have chosen this syntax
    - it will go in to the next alpha".

    My chief worry was throwing away one of the few unused ascii symbols,
    but if we take a look at perl6, there is a lot of promising unicode
    symbols to choose from in the future ;-). Also, there is still @(),
    @#, @{} and others in the hypothetical event BDFL would like to use @
    for future features like macros, ruby blocks or whatever.

    So I would vote +0 for @decorator if we were in the parallel universe
    where that mattered. Two days ago I was -10.

    --
    Ville Vainio http://tinyurl.com/2prnb
     
    Ville Vainio, Aug 7, 2004
    #1
    1. Advertising

  2. Ville Vainio

    AdSR Guest

    Ville Vainio <> wrote in message news:<>...
    > It might just be that @decorator might not be all that bad. When you
    > look at code that uses it it's not that ugly after all.


    You know what, I'm starting to feel the same. Yesterday Anthony Baxter
    mentioned this URL:

    http://mail.python.org/pipermail/python-dev/2004-August/047112.html

    where GvR says:

    """
    Given that the whole point of adding decorator syntax is to move the
    decorator from the end ("foo = staticmethod(foo)" after a 100-line
    body) to the front, where it is more in-your-face, it should IMO be
    moved all the way to the front.
    """

    And I had the sudden feeling that I finally got it. You see, for me,
    the @decorator syntax is a declaration - first thing that came to my
    mind was Pascal's "forward". So it says "take the def that follows and
    insert a (old style) decoration line in the code after it." Note that
    here the "def" is recursive - it may have other @decorators before it.

    I'm not sure I'm making myself clear; my understanding of it is more
    by feeling than by logic. So let's say that @decorator is like a
    preprocessor directive. If we have:

    @dec1
    @dec2
    def foo():
    pass

    then after the first pass it becomes:

    @dec2
    def foo():
    pass

    foo = dec1(foo)

    and after the second:

    def foo():
    pass

    foo = dec2(foo)

    foo = dec1(foo)

    BTW, this interpretation leaves some space for future manipulation of
    if/for/while/try statements.

    Speaking of loop statements, they have an optional else clause that
    isn't obvious either. It means "do this if there was no break-exit
    from the loop." Yet for me the obvious meaning would be "if there were
    no loop passes" - that is, the while condition was false on the first
    entry or the for list was empty. I think the word "finally" would be
    more to the point here (and it's a keyword anyway).

    I think having some obscurity in the language is inevitable. The
    present way of applying decorators (x = decor(x)) is equally cryptic
    to a newbie as the @decor syntax will be - first you have to know what
    a decorator is. There even aren't any decorators used in the standard
    lib - or at least grep doesn't show any static/classmethod rebindings.

    > My chief worry was throwing away one of the few unused ascii symbols,
    > but if we take a look at perl6, there is a lot of promising unicode
    > symbols to choose from in the future ;-). Also, there is still @(),
    > @#, @{} and others in the hypothetical event BDFL would like to use @
    > for future features like macros, ruby blocks or whatever.


    And we still have ? and $, plus the backtick (`) that now is for repr,
    but in Python 3000 will hopefully be for "os.popen.read(); ...close()"
    like in bash for example, or something equally useful.

    > So I would vote +0 for @decorator if we were in the parallel universe
    > where that mattered. Two days ago I was -10.


    Same here. I'm opposed to dictatorship in general - I grew up behind
    the Iron Curtain - but the BDFL's decisions so far were mostly
    beneficial, so I'll live with whatever he decides (I'm not saying this
    as seriously as it sounds).

    AdSR
     
    AdSR, Aug 8, 2004
    #2
    1. Advertising

  3. Ville Vainio

    Mark Bottjer Guest

    AdSR wrote:
    > You know what, I'm starting to feel the same. Yesterday Anthony
    > Baxter mentioned this URL:
    >
    > http://mail.python.org/pipermail/python-dev/2004-August/047112.html
    >
    > where GvR says:
    >
    > """ Given that the whole point of adding decorator syntax is to move
    > the decorator from the end ("foo = staticmethod(foo)" after a
    > 100-line body) to the front, where it is more in-your-face, it should
    > IMO be moved all the way to the front. """


    I saw this quote, too, but it did not sway me. I've felt ever since the
    C89 days that having too much stuff before the name being defined is an
    impediment to understanding the code:

    So, let's see here. We have a class method. It's memoized, it's
    transacted, and it's ACID. Okay, so far, so good. It's takes two ints,
    and returns an Exception. Okay. It was created on July 17, 2005, at
    3:13:32 in the morning EST, by a guy named Guido. Good to know.

    And it's named 'foo'. Which sucks, because I was looking for 'bar'.

    Where was I again?

    Having all this stuff before the *name* of the thing being defined is
    distracting. First tell me what it's *called*, then I'll decide if I
    want to know more or not.

    Ever look at Java code? Abominations like "public static final
    synchronized f() {}" litter the code. *shudder* How is one supposed to
    navigate code like this?

    > And I had the sudden feeling that I finally got it. You see, for me,
    > the @decorator syntax is a declaration - first thing that came to my
    > mind was Pascal's "forward". So it says "take the def that follows
    > and insert a (old style) decoration line in the code after it." Note
    > that here the "def" is recursive - it may have other @decorators
    > before it.


    That is the intent as I understand it. It even sounds reasonable, at
    first blush. But Python is not supposed to need forward declarations.
    And the other way of looking at it (an implicit stack of decorators held
    by the parser, to be applied to the "next X" found) is equally strange.

    Also, psychology tells us that people like to pick a starting location,
    and move in one direction from there. We're all familiar with this: this
    is how books are laid out. Having to scan *both* directions to see all
    the pertinent information is like having the chapter title in the middle
    of the chapter.

    I'll kick this horse once more: if we were take this prefix idea to it's
    logical conclusion, we'd put the function body before the function name!

    global x
    x *= a
    def f( a)

    This ain't Python to me.

    People don't do well with prefix or postfix; we want infix or
    sequential. That is why so many people still use "algebraic" calculators
    even when RPN is often faster and requires less button presses.
    Everything else in Python is either infix or sequential, why start
    prefixing stuff now?

    > Speaking of loop statements, they have an optional else clause that
    > isn't obvious either. It means "do this if there was no break-exit
    > from the loop." Yet for me the obvious meaning would be "if there
    > were no loop passes" - that is, the while condition was false on the
    > first entry or the for list was empty. I think the word "finally"
    > would be more to the point here (and it's a keyword anyway).


    Except that finally blocks *always* get executed; while else blocks get
    executed only if the loop completes normally. I agree that it is an odd
    word choice, but I assume they were simply trying to reuse a keyword.

    > I think having some obscurity in the language is inevitable. The
    > present way of applying decorators (x = decor(x)) is equally cryptic
    > to a newbie as the @decor syntax will be - first you have to know
    > what a decorator is. There even aren't any decorators used in the
    > standard lib - or at least grep doesn't show any static/classmethod
    > rebindings.


    Right. The only benefit of decorators is that they get the decoration
    closer to the start of the decorated. Locality matters when trying to
    understand code.

    -- Mark
     
    Mark Bottjer, Aug 9, 2004
    #3
  4. Ville Vainio

    Mark Bottjer Guest

    Mark Bottjer wrote:
    > AdSR wrote:
    >
    >> You know what, I'm starting to feel the same. Yesterday Anthony
    >> Baxter mentioned this URL:
    >>
    >> http://mail.python.org/pipermail/python-dev/2004-August/047112.html
    >>
    >> where GvR says:
    >>
    >> """ Given that the whole point of adding decorator syntax is to move
    >> the decorator from the end ("foo = staticmethod(foo)" after a
    >> 100-line body) to the front, where it is more in-your-face, it should
    >> IMO be moved all the way to the front. """


    Now combine this with this message, which I just found:

    http://mail.python.org/pipermail/python-dev/2004-August/047279.html

    where GvR says:

    """In the discussion on decorators months ago, solutions involving
    special syntax inside the block were ruled out early on. Basically,
    you shouldn't have to peek inside the block to find out important
    external properties of the function. (Yes, I know that docstrings
    violate this principle. For the record, it would be better if they
    were prefix too; and a prefix decorator syntax will let us fix this in
    the future but introducing a "doc" decorator.)"""

    So the position of the decorators is not open to debate. :(

    -- Mark
     
    Mark Bottjer, Aug 9, 2004
    #4
  5. Ville Vainio

    AdSR Guest

    (AdSR) wrote in message news:<>...
    > <snip>
    > @dec1
    > @dec2
    > def foo():
    > pass
    >
    > <snip>
    >
    > and after the second:
    >
    > def foo():
    > pass
    >
    > foo = dec2(foo)
    >
    > foo = dec1(foo)


    The latter is equivalent to:

    def foo():
    pass
    foo = dec1(dec2(foo))

    But I've just noticed that the spec says:

    """
    @f1
    @f2
    def func(): pass

    is equivalent to:

    def func(): pass
    func = f2(f1(func))
    """

    So the order is reverse, which breaks my previous interpretation. Oh, well...

    AdSR
     
    AdSR, Aug 9, 2004
    #5
  6. On Sunday 08 August 2004 18:28, Mark Bottjer wrote:
    > Having all this stuff before the *name* of the thing being defined is
    > distracting. First tell me what it's *called*, then I'll decide if I
    > want to know more or not.


    Much of that can be accomplished stylistically in the way comments are
    written (granted, that doesn't accomplish much for existing code that
    doesn't follow such conventions). But, for example, in my C/C++ code, I
    always have comments before my functions like so:

    /*
    * FooClass::foo()
    *
    * Fooifies the FooClass instance
    */
    int FooClass::foo(int parm1, char parm2, char *spam_name)
    ....

    Much of the problem (in any language, then) goes away. You still run
    into problems with existing code, though.

    -Michael
     
    Michael Ekstrand, Aug 9, 2004
    #6
  7. Ville Vainio

    Roy Smith Guest

    Michael Ekstrand <> wrote:

    > Much of that can be accomplished stylistically in the way comments are
    > written (granted, that doesn't accomplish much for existing code that
    > doesn't follow such conventions). But, for example, in my C/C++ code, I
    > always have comments before my functions like so:
    >
    > /*
    > * FooClass::foo()
    > *
    > * Fooifies the FooClass instance
    > */
    > int FooClass::foo(int parm1, char parm2, char *spam_name)


    The problem there is that you need to repeat the name of the function.
    This was one of the very reasons given for wanting to get away from

    def foo ():
    pass

    foo = classmethod (foo)

    in the first place. Not the only reason, by far, but certainly one of
    them.
     
    Roy Smith, Aug 9, 2004
    #7
  8. Ville Vainio

    Peter Hansen Guest

    Michael Ekstrand wrote:
    > Much of that can be accomplished stylistically in the way comments are
    > written (granted, that doesn't accomplish much for existing code that
    > doesn't follow such conventions). But, for example, in my C/C++ code, I
    > always have comments before my functions like so:
    >
    > /*
    > * FooClass::foo()
    > *
    > * Fooifies the FooClass instance
    > */
    > int FooClass::foo(int parm1, char parm2, char *spam_name)
    > ...
    >
    > Much of the problem (in any language, then) goes away. You still run
    > into problems with existing code, though.


    But it brings other problems. There's a principle called DRY,
    for Don't Repeat Yourself, which comes from observations that
    *any* repetition will lead to maintenance problems and other
    difficulties, especially when refactoring code. And I can't
    count the number of times I've seen comments such as the above
    which were wrong, either through name changes or because of
    the inevitable cut-and-paste errors.

    At my last place of employment, we abolished all redundant
    comments, such as those containing the name of the function or
    module. The code got much shorter and cleaner.

    -Peter
     
    Peter Hansen, Aug 9, 2004
    #8
  9. On 9 Aug 2004 07:07:54 -0700, (AdSR) wrote:

    > (AdSR) wrote in message news:<>...
    >> <snip>
    >> @dec1
    >> @dec2
    >> def foo():
    >> pass
    >>
    >> <snip>
    >>
    >> and after the second:
    >>
    >> def foo():
    >> pass
    >>
    >> foo = dec2(foo)
    >>
    >> foo = dec1(foo)

    >
    >The latter is equivalent to:
    >
    >def foo():
    > pass
    >foo = dec1(dec2(foo))
    >
    >But I've just noticed that the spec says:
    >
    >"""
    >@f1
    >@f2
    >def func(): pass
    >
    >is equivalent to:
    >
    >def func(): pass
    >func = f2(f1(func))
    >"""
    >
    >So the order is reverse, which breaks my previous interpretation. Oh, well...
    >

    I think your example is not from the PEP. What "spec" are you citing?
    Note the order in the example cut and pasted from the current
    (Last-Modified: 2004/08/06 18:34:15) pep 318:
    ----
    The current syntax for function decorators as implemented in Python 2.4a2 is:

    @dec2
    @dec1
    def func(arg1, arg2, ...):
    pass

    This is equivalent to:

    def func(arg1, arg2, ...):
    pass
    func = dec2(dec1(func))
    ----

    Regards,
    Bengt Richter
     
    Bengt Richter, Aug 9, 2004
    #9
  10. Ville Vainio

    AdSR Guest

    (Bengt Richter) wrote in message news:<cf87jt$bra$0$>...
    > On 9 Aug 2004 07:07:54 -0700, (AdSR) wrote:
    > <snip>
    > >So the order is reverse, which breaks my previous interpretation. Oh, well...
    > >

    > I think your example is not from the PEP. What "spec" are you citing?


    http://www.python.org/dev/doc/devel/ref/function.html
     
    AdSR, Aug 10, 2004
    #10
  11. On 10 Aug 2004 03:18:54 -0700, (AdSR) wrote:

    > (Bengt Richter) wrote in message news:<cf87jt$bra$0$>...
    >> On 9 Aug 2004 07:07:54 -0700, (AdSR) wrote:
    >> <snip>
    >> >So the order is reverse, which breaks my previous interpretation. Oh, well...
    >> >

    >> I think your example is not from the PEP. What "spec" are you citing?

    >
    >http://www.python.org/dev/doc/devel/ref/function.html


    I guess that should be fixed. IIUC. Per BDFL:

    http://mail.python.org/pipermail/python-dev/2004-August/047521.html

    I still think a di-glyph with an opening paren would give the feel of
    the nesting effect (inner before outer) better than @ -- e.g.,

    decofunexpr1(=
    decofunexpr2(=
    def foo(): pass

    for effect foo = decofunexpr1(decofunexpr2(foo))

    (I started with ':)' but tools are sensitive to ':' I guess, so above uses '(='

    Regards,
    Bengt Richter
     
    Bengt Richter, Aug 10, 2004
    #11
  12. (AdSR) wrote:
    > (Bengt Richter) wrote in message news:<cf87jt$bra$0$>...
    > > On 9 Aug 2004 07:07:54 -0700, (AdSR) wrote:
    > > <snip>
    > > >So the order is reverse, which breaks my previous interpretation. Oh, well...
    > > >

    > > I think your example is not from the PEP. What "spec" are you citing?

    >
    > http://www.python.org/dev/doc/devel/ref/function.html


    That part of the reference manual says:

    """
    If there are multiple decorators, they are applied in reverse order.
    For example, the following code:

    @f1
    @f2
    def func(): pass

    is equivalent to:

    def func(): pass
    func = f2(f1(func))
    """

    I believe that in the example the author may have got confused by the
    visual appearance of the expression f2(f1(func)). It's the order of
    *application* that is the key thing and this expression actually has
    f1 being applied first, rather than f2 as mandated by the "apply in
    reverse order" rule. The example should instead have given the
    equivalent expression as f1(f2(func)).


    Hamish Lawson
     
    Hamish Lawson, Aug 10, 2004
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Guest
    Replies:
    5
    Views:
    620
  2. Istvan Albert
    Replies:
    17
    Views:
    456
    Reinhold Birkenfeld
    Aug 7, 2004
  3. Delaney, Timothy C (Timothy)

    RE: Poll - Vote here for "list-after-def" (was Decorator syntax)

    Delaney, Timothy C (Timothy), Aug 6, 2004, in forum: Python
    Replies:
    3
    Views:
    278
    Anthony Baxter
    Aug 6, 2004
  4. Anthony Baxter
    Replies:
    3
    Views:
    295
    Anthony Baxter
    Aug 6, 2004
  5. glomde
    Replies:
    5
    Views:
    525
    glomde
    Mar 29, 2007
Loading...

Share This Page