FAQ
Hello,

I'm pleased to see activity on this topic as it pains me to write
"classmethod" two pages of code after the method definition. However I
find the decorators to obfuscate the syntax and lessen the expressivity
(ie. they restrain what can be done).

All these problems come from the fact that the execution of the
"foo=staticmethod(foo)" must be delayed after the execution of the "def"
statement because it must act on the function after it has been defined.

Normal program execution thus flow forces it to be placed after the
"def", while readability would require it to be placed *before* the 'def'.

How to reverse the execution order ? One method would be to use an
expression, but that would get very ugly soon, and Python's indented
syntax does not lend itself well to such twistings. To mix a few previous
postings :

mymethod = staticmethod( def (args):
method code...
)

is just plain ugly.

mymethod = staticmethod( def (args) ):
method code...

is also quite ugly.

I don't like the decorators either.

So the root of the problem is the fact that the source code executes from
top to bottom. I see two solutions.
1. Use a text editor which can fold functions, hiding the code between
the def and the staticmethod call
2. Reverse the flow of code.

Ha.
I'm gonna propose a flame bait, read on. It's about code blocks.

Say we introduce a new keyword : 'block'. Here is the syntax :

block (block-class,block-name):
some code
some code
some code

A block of code is thus an object, deriving from a base class (say,
'CodeBlock'). It can have children too (other blocks of code), which can
have names.
If omitted, block-class defaults to CodeBlock, and block-name to None.
(block-class,block-name) is a tuple, so the following are equivalent :

block-class => (block-class,None)
block-class,block-name => (block-class,block-name)
(,block-name) => (CodeBlock,block-name)

Example in the classmethod thingie :

block InvertingCodeBlock:
block:
mymethod = staticmethod(mymethod):
block:
def mymethod(arg1, arg2):
some code

where InvertingCodeBlock: is a block class which executes its children in
inverted order. This object has two children, both of class CodeBlock.

I invented the syntax as it came, it sucks, but it's just so you get the
idea. Feel free to propose something better. But first look at the
following.

Now, this has other, more interesting, things into it.
Example :

def crapthread( params ):
acquire_lock( global_lock )
do something
release_lock( global_lock )

This example sucks because any exception happening in "do something" will
not release the lock, and the lock must be manually released before every
return.

Now, CodeBlock can have children. What if CodeBlock decides the children
could be executed in a certain order ?
For instance, we could have children names "init", "run", "cleanup" which
would run in this order.
We could then write :

def crapthread( params ):
block:
block (,'init'):
acquire_lock( global_lock )
block (,'run'):
do something
block (,'cleanup'):
release_lock( global_lock )

I expect anyone will understand how this works. The parent block would
execute 'init', then 'run', then 'cleanup', then pass anu return'ed value
or exceptions.

If the 'def' statement implies creation of a code block, we could omit
the first 'block:'

The classmethod example cound be rewritten as :
block:
block (,'init'):
mymethod = staticmethod(mymethod):
block (,'run'):
def mymethod(arg1, arg2):
some code

We could define other types of children too, like a version of cleanup
which is executed oly when no exceptions occur in "run".

Now let's add the __currentblock__ which gives us a reference to the
block we're in, and give the block object a way to add children of a
certain type. We could thus register cleanup actions to be executed at the
end of a function when needed.

try-except-finally could also be done with blocks.

All this is very preliminary thinking. I hope it fuels your inspiration.
I feel this could be powerful, and also pythonic. What do you think ?

Thanks for your time,

Pierre

Search Discussions

  • Sean Ross at Mar 27, 2004 at 7:11 pm
    "PF" <peufeu at free.fr> wrote in message news:opr5jagci1b723ru at news.free.fr...
    Hello,

    I'm pleased to see activity on this topic as it pains me to write
    "classmethod" two pages of code after the method definition. However I
    find the decorators to obfuscate the syntax and lessen the expressivity
    (ie. they restrain what can be done).

    All these problems come from the fact that the execution of the
    "foo=staticmethod(foo)" must be delayed after the execution of the "def"
    statement because it must act on the function after it has been defined.

    Normal program execution thus flow forces it to be placed after the
    "def", while readability would require it to be placed *before* the 'def'.

    How to reverse the execution order ? One method would be to use an
    expression, but that would get very ugly soon, and Python's indented
    syntax does not lend itself well to such twistings. To mix a few previous
    postings :

    mymethod = staticmethod( def (args):
    method code...
    )

    is just plain ugly.

    mymethod = staticmethod( def (args) ):
    method code...

    is also quite ugly.

    I don't like the decorators either.

    So the root of the problem is the fact that the source code executes from
    top to bottom. I see two solutions.

    Check out "Re: Meta-class fun with PEP 318 [was Re: PEP 318 - posting
    draft]", for another solution, but only for methods.

    decorate("g", staticmethod)
    def g():
    return "G"

    Sean
  • John Roth at Mar 27, 2004 at 8:56 pm
    "PF" <peufeu at free.fr> wrote in message news:opr5jagci1b723ru at news.free.fr...
    Hello,

    I'm pleased to see activity on this topic as it pains me to write
    "classmethod" two pages of code after the method definition. However I
    find the decorators to obfuscate the syntax and lessen the expressivity
    (ie. they restrain what can be done).
    Why are you writing methods that long? (That's rhetorical -
    I'd break it up so I could understand it)
    All these problems come from the fact that the execution of the
    "foo=staticmethod(foo)" must be delayed after the execution of the "def"
    statement because it must act on the function after it has been defined.
    That isn't the only problem, but it's the one most often cited.
    Normal program execution thus flow forces it to be placed after the
    "def", while readability would require it to be placed *before* the 'def'.
    I'd prefer it as part of the same expression as the 'def'. That makes it
    quite clear, and eliminates any possible confusion from having two
    assignments where one should be sufficient.
    How to reverse the execution order ? One method would be to use an
    expression, but that would get very ugly soon, and Python's indented
    syntax does not lend itself well to such twistings. To mix a few previous
    postings :

    mymethod = staticmethod(def(args):
    method code...
    )

    is just plain ugly.
    Agreed. I don't like the trailing parenthesis on another line.
    Avoiding that is part of the joy of Python. (Notice that
    I've reworked your example to conform to Guido's style
    rules.)
    mymethod = staticmethod(def(args)):
    method code...
    is also quite ugly.
    Why? Except for the ':', which I would eliminate (although
    there are arguements for keeping it) I think it reads quite well.
    I don't like the decorators either.
    Neither do I. I don't find that any version of the syntax flows.
    So the root of the problem is the fact that the source code executes from
    top to bottom. I see two solutions.
    1. Use a text editor which can fold functions, hiding the code between
    the def and the staticmethod call
    That doesn't fix it; there's still two statements where there should
    be only one.
    2. Reverse the flow of code.
    I'm going to stop here and go off in another direction...
    [snip rest of post]

    As I said above, I find:

    aMethod = staticmethod(def(parms))
    statements

    to be quite readable. The indentation says everything I need
    said to understand it while scanning without having to resort
    to studying the syntax (which I would have to do with brace-
    bound languages.)

    Multiple decorators fall out without any effort. There are
    really only two issues:

    1. The lack of a ":" at the end.

    2. How to handle multiple blocks in one expression.

    On item 1. There are two good reasons for the ":":
    readability and the fact that most Python aware editors
    use it for automatic indentation.

    Regardless of what happens, readability is going to take
    a hit, and the editors can be patched.

    The way to handle item 2 is with the following set of
    indentation rules:

    1. There may be at most one 'def' on a line (*not* in a
    statement!)

    2. If the expression containing the def does not end naturally
    on the same line as the ')' at the end of the def, parsing of
    the expression is suspended at the end of that line (*not*
    immediately after the ')'. The reason for this rule is to allow
    the containing statement to end in the most readable fashion,
    if possible.

    3. The statements for the def follow immediately
    on the next line and following lines, indented either 1 or 2
    levels depending on whether the containing expression ended
    or was suspended.

    4. The body of the function/method ends, as usual, when
    any line is indented less (that is, farther to the left) than the
    body of the function/method.

    5. A suspended expression continues on the line immediately
    after the end of the function body. It must be indented to the
    left of the function body, and to the right of the indentation for
    the statement containing the expression.

    In looking at this, I see one other problem: a multi-line
    statement that contains several lines after the last one that
    contains a 'def'. My personal preference is that I can finish
    out the statement before writing the function body, but I
    don't see a way of managing both multiple blocks in one
    expression and doing this.

    Finally, I have another reason for liking this particular
    syntax. It lets me stick methods into instances quite
    directly, without having to invent yet another syntax, or
    leaving them bound at the module level to both be bound
    into the instance and also cleaned up from the module.
    That's something that I need for certain kinds of programs
    that are more easily expressed with a proto-type based
    language, such as interactive fiction.

    John Roth
    Pierre
  • Stephen Horne at Mar 28, 2004 at 12:11 am

    On Sat, 27 Mar 2004 15:56:18 -0500, "John Roth" wrote:


    "PF" <peufeu at free.fr> wrote in message news:opr5jagci1b723ru at news.free.fr...
    Hello,

    I'm pleased to see activity on this topic as it pains me to write
    "classmethod" two pages of code after the method definition. However I
    find the decorators to obfuscate the syntax and lessen the expressivity
    (ie. they restrain what can be done).
    Why are you writing methods that long? (That's rhetorical -
    I'd break it up so I could understand it)
    While readable methods tend to be short methods, breaking up a method
    without good reason can also damage readability. Also, having many
    simple units doesn't remove complexity - it merely means that the
    complexity is in the interaction between units. And if readers can
    only understand the units one or two at a time, and don't understand
    how the units interact, it follows that the code as a whole isn't
    readable.

    I've seen this problem more times than I care to mention. You look at
    module A and it all makes sense and looks fine. You look at module B
    and it all makes sense and looks fine. You look at modules A and B
    together and you can spot the incompatibility - the difference in the
    assumptions made in each module about the interactions between them.
    But when there are 100 much simpler modules, and a dozen or more play
    some role in the incompatibility, suddenly its much harder to
    understand how the incompatibility arises.

    Keeping related code and definitions together is a good principle. But
    that applies just as much to two pieces of related function body code
    as it does to a function definition and its wrapper. If you routinely
    split long functions purely for reasons like keeping the wrapping
    statement close to the definition of the function it wraps, or out of
    the principle that methods should be short, then that's fine. But
    don't expect me to read it.

    All things are a balance in programming, as in life. Strong principles
    can get you only so far - if you impose absolute principles on
    everyone and in every case, often they will do more damage than good.
    mymethod = staticmethod(def(args)):
    method code...
    is also quite ugly.
    Why? Except for the ':', which I would eliminate (although
    there are arguements for keeping it) I think it reads quite well.
    Mainly because the method code appears to be associated with the
    assignment, or the assigned variable, rather than the def. It's hard
    (maybe impossible?) to name a block structure in any language that
    doesn't start with a word that identifies the type of block. Probably
    the only common statements of any type that don't start with an
    identifying keyword are assignments. That isn't a fluke.

    Anyone pointing out the streaming operators in C++ gets half a point.
    Strictly they're just operators in an expression, but they get used in
    such an imperitive way that I half count them as statements.
    I don't like the decorators either.
    Neither do I. I don't find that any version of the syntax flows.
    There is a certain lack of beauty, I agree. But while there is beauty
    in simplicity, there is pragmatism in realising that not all
    complexity can be avoided.

    2. How to handle multiple blocks in one expression. <snip>
    The way to handle item 2 is with the following set of
    indentation rules:
    I disagree.

    There are two common cases I can think of where names are used before
    they are defined. One is mathematics (y = mx + c, where x is ...) and
    the other is Haskell, working on much the same principle.

    There is a certain similarity of purpose in the Pascal 'with' block,
    in that the Haskell 'where', like the Pascal 'with', is mainly used
    for abbreviation - though the means is rather different.

    Messing around with these principles, I came up with...

    with x :
    x = staticmethod(x)
    where def x (args) :
    ...

    But virtually the only suggestion I prefer this to is yours, I'm
    afraid :-(
    5. A suspended expression continues on the line immediately
    after the end of the function body. It must be indented to the
    left of the function body, and to the right of the indentation for
    the statement containing the expression.
    This suggestion is IMO close to insane.

    You are breaking up a statement and putting potentially quite large
    chunks of body code in the middle of it - maybe several function
    bodies. And you are doing this to avoid having code between the
    function definition and its wrapping assignment.

    In other words, you are deliberately splitting up closely related code
    in order to avoid splitting up closely related code. And making the
    lexical structure and layout of Python code more complex in order to
    do it.

    If you limit it to the case where a single statement containing a
    single def can be followed by the body code, then it isn't actually
    insane (though I'm still strongly against it) but if you have two
    functions being manipulated by the same wrapping code (I don't see the
    need, but lets go with it anyway) then one way or another the wrapping
    code is going to be separated from at least one functions body. In
    this case, referring to the functions by name is the only thing that
    makes sense. We don't need any new syntax to do that.


    --
    Steve Horne

    steve at ninereeds dot fsnet dot co dot uk

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedMar 27, '04 at 6:46p
activeMar 28, '04 at 12:11a
posts4
users4
websitepython.org

People

Translate

site design / logo © 2022 Grokbase