*If* we're going to create syntax for anonymous blocks, I think the primary use case ought to be cleanup operations to replace try/finally blocks for locking and similar things. I'd love to have syntactical support so I can write
I heartily agree! Especially when you have very similar try/finally code you use in many places, and wish to refactor it into a common area. If this is done, you are forced into a callback form like follows::
def withFile(filename, callback): aFile = open(filename, 'r') try: result = callback(aFile) finally: aFile.close() return result
class Before: def readIt(self, filename): def doReading(aFile): self.readPartA(aFile) self.readPartB(aFile) self.readPartC(aFile)
withFile(filename, doReading)
Which is certainly functional. I actually use the idiom frequently. However, my opinion is that it does not read smoothly. This form requires that I say what I'm doing with something before I know the context of what that something is. For me, blocks are not about shortening the code, but rather clarifying *intent*. With this proposed change, the code becomes::
class After: def readIt(self, filename): withFile(filename): self.readPartA(aFile) self.readPartB(aFile) self.readPartC(aFile)
In my opinion, this is much smoother to read. This particular example brings up the question of how arguments like "aFile" get passed and named into the block. I anticipate the need for a place to put an argument declaration list. ;) And no, I'm not particularly fond of Smalltalk's solution with "| aFile |", but that's just another opinion of aesthetics.
Another set of question arose for me when Barry started musing over the combination of blocks and decorators. What are blocks? Well, obviously they are callable. What do they return? The local namespace they created/modified? How do blocks work with control flow statements like "break", "continue", "yield", and "return"? I think these questions have good answers, we just need to figure out what they are. Perhaps "break" and "continue" raise exceptions similar to StopIteration in this case?
As to the control flow questions, I believe those answers depend on how the block is used. Perhaps a few different invocation styles are applicable. For instance, the method block.suite() could return a tuple such as (returnedValue, locals()), where block.__call__() would simply return like any other callable.
It would be good to figure out what the control flow difference is between::
def readAndReturn(self, filename): withFile(filename): a = self.readPartA(aFile) b = self.readPartB(aFile) c = self.readPartC(aFile) return (a, b, c)
and::
def readAndReturn(self, filename): withFile(filename): a = self.readPartA(aFile) b = self.readPartB(aFile) c = self.readPartC(aFile) return (a, b, c)
Try it with yield to further vex the puzzle. ;)
Thanks for your time! -Shane Holloway _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com