Re: [Python-Dev] defmacro (was: Anonymous blocks)
Michael Chermside wrote: I've been following this conversation, and it sounds to me as if we are stumbling about in the dark, trying to feel our way toward something very useful and powerful. I think Jim is right, what we're feeling our way toward is macros. I considered saying something like that about 3 posts ago, but I was afraid of getting stoned for heresy... ... Eventually, there would develop a large number of different Python dialects (as some claim has happened in the Lisp community) each dependent on macros the others lack. The most important casualty would be Python's great *readability*. In other words, rather than hearing what we'd like to be able to DO with blocks, I'd like to hear what we want to PROHIBIT DOING with blocks. From that quote, it would seem what we want to do is prohibit anything that would make code less readable. Or prohibit anything that would permit creating a new dialect. Or something. -- Greg Ewing, Computer Science Dept, +--+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | [EMAIL PROTECTED] +--+ ___ 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
Re: [Python-Dev] defmacro (was: Anonymous blocks)
Michael Chermside wrote: if the answer is that we want to prohibit nothing, then the right solution is macros. I'm not sure about that. Smalltalk manages to provide very reasonable-looking user-defined control structures without using compile-time macros, just normal runtime evaluation together with block arguments. It does this by starting out with a fairly minimal and very flexible syntax. This raises the question of why people feel the need for macros in Lisp or Scheme, which have an even more minimal and flexible syntax. I think part of the reason is that the syntax for passing an unevaluated block is too obtrusive. In Scheme you can define a function (not macro) that is used like this: (with-file foo/blarg (lambda (f) (do-something-with f))) But there is a natural tendency to want to be able to cut out the lambda cruft and just write something like: (with-file foo/blarg (f) (do-something-with f)) and for that you need a macro. The equivalent in Smalltalk would be something like File open: foo/blarg do: [:f f something] which doesn't look too bad (compared to the rest of the language!) because the block-passing syntax is fairly unobtrusive. So in summary, I don't think you necessarily *need* macros to get nice-looking user-defined control structures. It depends on other features of the language. -- Greg Ewing, Computer Science Dept, +--+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | [EMAIL PROTECTED] +--+ ___ 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
Re: [Python-Dev] defmacro (was: Anonymous blocks)
[ Michael Walter ]: A couple of examples out of my tired head (solely from a user perspective) :-) Embedding domain specific language (ex.: state machine): ... Embedding domain specific language (ex.: markup language): ... Embedding domain-specific language (ex.: badly-designed database table): ... ..., which might actually prove someone's point that the language designer shouldn't allow people to do such things. The whole macros issue comes to a tradeoff between power+expressiviness X readability. IMVHO, macros are readability assassins. The power (for any developer) to introduce new syntax is *not* a desirable feature, but something to be avoided. And that alone should be a stronger argument than a hundred use cases. cheers, Senra -- Rodrigo Senra -- MSc Computer Engineerrodsenra(at)gpr.com.br GPr Sistemas Ltdahttp://www.gpr.com.br/ Personal Blog http://rodsenra.blogspot.com/ ___ 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
[Python-Dev] defmacro (was: Anonymous blocks)
(3) Add macros. We still have to figure out how to limit their obfuscation. nobody has given even a *remotely* plausible mechanism for how exactly you would get code executed at compile time. macros can (and *possibly* should) be evaluated at run-time. We must still have very different views on what a macro is. In a compiled language, it is (necessarily) compiled. In an interpreted language, it doesn't have to be. After a macros is run, there is new syntax that needs to be parsed and compiled to bytecode. ... anything that requires invoking the compiler each time a macro is used will be so slow that nobody will want to use it. I had been thinking that the typical use would be during function (or class) definition. The overhead would be similar to that of decorators, and confined mostly to module loading. I do see your point that putting a macro call inside a function could be slow -- but I'm not sure that is a reason to forbid it. Even if the macros just rerun the same boilerplate code less efficiently, it is still good to have that boilerplate defined once, instead of cutting and pasting. Or, at least, it is better *if* that once doesn't become unreadable in the process. I am unable to assess the value of this mechanism unless you make a concrete proposal. You seem to have something in mind but you're not doing a good job getting it into mine... I'm not confident that macros are even a good idea; I just don't want a series of half-macros. That said, here is a strawman. defmacro boiler1(name, rejects): def %(name) (*args): for a in args: if a in %(rejects): print Don't send me %s % a ... boiler1(novowels, aeiouy) boiler2(nokey5, jkl) I'm pretty sure that a real version should accept suites instead of just arguments, and the variable portion might even be limited to suites (as in the thunk discussion). It might even be reasonable to mark macro calls as different from function calls. template novowels from boiler1(aeiou): suite but I can't help thinking that multiple suites should be possible, and then they should be named, and ... that spurred at least one objection. http://mail.python.org/pipermail/python-dev/2005-April/052949.html -jJ ___ 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
Re: [Python-Dev] defmacro (was: Anonymous blocks)
Jim Jewett wrote: I had been thinking that the typical use would be during function (or class) definition. The overhead would be similar to that of decorators, and confined mostly to module loading. But that's too late, unless you want to resort to bytecode hacking. By the time the module is loaded, its source code has long since been compiled into code objects. -- Greg Ewing, Computer Science Dept, +--+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | [EMAIL PROTECTED] +--+ ___ 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
RE: [Python-Dev] defmacro (was: Anonymous blocks)
Jim Jewett writes: As best I can tell, the anonymous blocks are used to take care of boilerplate code without changing the scope -- exactly what macros are used for. Folks, I think that Jim is onto something here. I've been following this conversation, and it sounds to me as if we are stumbling about in the dark, trying to feel our way toward something very useful and powerful. I think Jim is right, what we're feeling our way toward is macros. The problem, of course, is that Guido (and others!) are on record as being opposed to adding macros to Python. (Even good macros... think lisp, not cpp.) I am not quite sure that I am convinced by the argument, but let me see if I can present it: Allowing macros in Python would enable individual programmers or groups to easily invent their own syntax. Eventually, there would develop a large number of different Python dialects (as some claim has happened in the Lisp community) each dependent on macros the others lack. The most important casualty would be Python's great *readability*. (If this is a strawman argument, i.e. if you know of a better reason for keeping macros OUT of Python please speak up. Like I said, I've never been completely convinced of it myself.) I think it would be useful if we approached it like this: either what we want is the full power of macros (in which case the syntax we choose should be guided by that choice), or we want LESS than the full power of macros. If we want less, then HOW less? In other words, rather than hearing what we'd like to be able to DO with blocks, I'd like to hear what we want to PROHIBIT DOING with blocks. I think this might be a fruitful way of thinking about the problem which might make it easier to evaluate syntax suggestions. And if the answer is that we want to prohibit nothing, then the right solution is macros. -- Michael Chermside ___ 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
Re: [Python-Dev] defmacro (was: Anonymous blocks)
Michael Chermside wrote: Jim Jewett writes: As best I can tell, the anonymous blocks are used to take care of boilerplate code without changing the scope -- exactly what macros are used for. Folks, I think that Jim is onto something here. I've been following this conversation, and it sounds to me as if we are stumbling about in the dark, trying to feel our way toward something very useful and powerful. I think Jim is right, what we're feeling our way toward is macros. I am very excited about the discussion of blocks. I think they can potentially address two things that are sticky to express in python right now. The first is to compress the common try/finally use cases around resource usage as with files and database commits. The second is language extensibility, which makes us think of what macros did for Lisp. Language extensibility has two motivations. First and foremost is to allow the programmer to express his or her *intent*. The second motivation is to reuse code and thereby increase productivity. Since methods already allow us to reuse code, our motivation is to increase expressivity. What blocks offer is to make Python's suites something a programmer can work with. Much like using a metaclass putting control of class details into the programmer's hands. Or decorators allowing us to modify method semantics. If the uses of decorators tells us anything, I'm pretty sure there are more potential uses of blocks than we could shake many sticks at. ;) So, the question comes back to what are blocks in the language extensibility case? To me, they would be something very like a code object returned from the compile method. To this we would need to attach the globals and locals where the block was from. Then we could use the normal exec statement to invoke the block whenever needed. Perhaps we could add a new mode 'block' to allow the ControlFlow exceptions mentioned elsewhere in the thread. We still need to find a way to pass arguments to the block so we are not tempted to insert them in locals and have them magically appear in the namespace. ;) Personally, I'm rather attached to as (x, y): introducing the block. To conclude, I mocked up some potential examples for your entertainment. ;) Thanks for your time and consideration! -Shane Holloway Interfaces:: def interface(interfaceName, *bases, ***aBlockSuite): blockGlobals = aBlockSuite.globals().copy() blockGlobals.update(aBlockSuite.locals()) blockLocals = {} exec aBlock in blockGlobals, blockLocals return iterfaceType(interfaceName, bases, blockLocals) IFoo = interface('IFoo'): def isFoo(self): pass IBar = interface('IBar'): def isBar(self): pass IBaz = interface('IBaz', IFoo, IBar): def isBaz(self): pass Event Suites:: def eventSinksFor(events, ***aBlockSuite): blockGlobals = aBlockSuite.globals().copy() blockGlobals.update(aBlockSuite.locals()) blockLocals = {} exec aBlock in blockGlobals, blockLocals for name, value in blockLocals.iteritems(): if aBlockSuite.locals().get(name) is value: continue if callable(value): events.addEventFor(name, value) def debugScene(scene): eventSinksFor(scene.events): def onMove(pos): print pos:, pos def onButton(which, state): print button:, which, state def onKey(which, state): print key:, which, state ___ 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
Re: [Python-Dev] defmacro (was: Anonymous blocks)
On Mon, Apr 25, 2005, Shane Holloway (IEEE) wrote: Interfaces:: def interface(interfaceName, *bases, ***aBlockSuite): blockGlobals = aBlockSuite.globals().copy() blockGlobals.update(aBlockSuite.locals()) blockLocals = {} exec aBlock in blockGlobals, blockLocals return iterfaceType(interfaceName, bases, blockLocals) IFoo = interface('IFoo'): def isFoo(self): pass Where does ``aBlock`` come from? -- Aahz ([EMAIL PROTECTED]) * http://www.pythoncraft.com/ It's 106 miles to Chicago. We have a full tank of gas, a half-pack of cigarettes, it's dark, and we're wearing sunglasses. Hit it. ___ 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
[Python-Dev] defmacro (was: Anonymous blocks)
Guido: My problem with macros is actually more practical: Python's compiler is too dumb. I am assuming that we want to be able to import macros from other modules, and I am assuming that macros are expanded by the compiler, not at run time; but the compiler doesn't follow imports ... Expanding at run-time is less efficient, but it works at least as well semantically. If today's alternative is manual cut-n-paste, I would still rather have the computer do it for me, to avoid accidental forks. It could also be done (though not as cleanly) by making macros act as import hooks. import defmacro# Stop processing until defmacro is loaded. # All future lines will be preprocessed by the # hook collection ... from defmacro import foo # installs a foo hook, good for the rest of the file Michael Chermside: I think it would be useful if we approached it like this: either what we want is the full power of macros (in which case the syntax we choose should be guided by that choice), or we want LESS than the full power of macros. If we want less, then HOW less? In other words, rather than hearing what we'd like to be able to DO with blocks, I'd like to hear what we want to PROHIBIT DOING with blocks. I think this might be a fruitful way of thinking about the problem which might make it easier to evaluate syntax suggestions. And if the answer is that we want to prohibit nothing, then the right solution is macros. I'm personally at a loss understanding your question here. Perhaps you could try answering it for yourself? Why not just introduce macros? If the answer is We should, it is just hard to code, then use a good syntax for macros. If the answer is We don't want xx sss (S\! 2k3 ] to ever be meaningful, then we need to figure out exactly what to prohibit. Lisp macros are (generally, excluding read macros) limited to taking and generating complete S-expressions. If that isn't enough to enforce readability, then limiting blocks to expressions (or even statements) probably isn't enough in python. Do we want to limit the changing part (the anonymous block) to only a single suite? That does work well with the yield syntax, but it seems like an arbitrary restriction unless *all* we want are resource wrappers. Or do we really just want a way to say that a function should share its local namespace with it's caller or callee? In that case, maybe the answer is a lexical or same_namespace keyword. Or maybe just a recipe to make exec or eval do the right thing. def myresource(rcname, callback, *args): rc=open(rcname) same_namespace callback(*args) close(rc) def process(*args): ... ... if __name__ == '__main__': myresource(file1, process, arg1, arg2) ___ 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
RE: [Python-Dev] defmacro (was: Anonymous blocks)
Guido writes: My problem with macros is actually more practical: Python's compiler is too dumb. I am assuming that we want to be able to import macros from other modules, and I am assuming that macros are expanded by the compiler, not at run time; but the compiler doesn't follow imports (that happens at run time) so there's no mechanism to tell the compiler about the new syntax. And macros that don't introduce new syntax don't seem very interesting (compared to what we can do already). That's good to hear. It expresses fairly clearly what the challenges are in implementing macros for Python, and expressing the challenges makes it easier to attack the problem. My interest comes because some recent syntax changes (generators, generator expressions) have seemed to me like true language changes, but others (decorators, anonymous-blocks) to me just cry out this would be easy as a macro!. I wrote: I think it would be useful if we approached it like this: either what we want is the full power of macros (in which case the syntax we choose should be guided by that choice), or we want LESS than the full power of macros. If we want less, then HOW less? In other words, rather than hearing what we'd like to be able to DO with blocks, I'd like to hear what we want to PROHIBIT DOING with blocks. I think this might be a fruitful way of thinking about the problem which might make it easier to evaluate syntax suggestions. And if the answer is that we want to prohibit nothing, then the right solution is macros. Guido replied: I'm personally at a loss understanding your question here. Perhaps you could try answering it for yourself? You guys just think too fast for me. When I started this email, I replied Fair enough. One possibility is But while I was trying to condense my thoughts down from 1.5 pages to something short and coherent (it takes time to write it short) everything I was thinking became obscelete as both Paul Moore and Jim Jewett did exactly the kind of thinking I was hoping to inspire: Paul: What I feel is the key concept here is that of injecting code into a template form (try...finally, or try..except..else, or whatever) [...] Specifically, cases where functions aren't enough. If I try to characterise precisely what those cases are, all I can come up with is when the code being injected needs to run in the current scope, not in the scope of a template function. Is that right? Jim: Why not just introduce macros? If the answer is We should, it is just hard to code, then use a good syntax for macros. If the answer is We don't want xx sss (S\! 2k3 ] to ever be meaningful, then we need to figure out exactly what to prohibit. [...] Do we want to limit the changing part (the anonymous block) to only a single suite? That does work well with the yield syntax, but it seems like an arbitrary restriction unless *all* we want are resource wrappers. Or do we really just want a way to say that a function should share its local namespace with it's caller or callee? In that case, maybe the answer is a lexical or same_namespace keyword. My own opinion is that we DO want macros. I prefer a language have a few, powerful constructs rather than lots of specialized ones. (Yet I still believe that doing different things should look different... which is why I prefer Python to Lisp.) I think that macros could solve a LOT of problems. There are lots of things one might want to replace within macros, from identifiers to punctuation, but I'd be willing to live with just two of them: expressions, and series-of-statements (that's almost the same as a block). There are only two places I'd want to be able to USE a macro: where an expression is called for, and where a series-of-statements is called for. In both cases, I'd be happy with a function-call like syntax for including the macro. Well, that's a lot of wanting... now I all I need to do is invent a clever syntax that allows these in an elegant fashion while also solving Guido's point about imports (hint: the answer is that it ALL happens at runtime). I'll go think some while you guys zoom past me again. wink -- Michael Chermside ___ 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
Re: [Python-Dev] defmacro (was: Anonymous blocks)
Robert Brewer wrote: So currently, all subclasses just override __set__, which leads to a *lot* of duplication of code. If I could write the base class' __set__ to call macros like this: def __set__(self, unit, value): self.begin() if self.coerce: value = self.coerce(unit, value) oldvalue = unit._properties[self.key] if oldvalue != value: self.pre() unit._properties[self.key] = value self.post() self.end() defmacro begin: pass defmacro pre: pass defmacro post: pass defmacro end: pass Here is a way to write that using anonymous blocks: def __set__(self, unit, value): with self.setting(unit, value): if self.coerce: value = self.coerce(unit, value) oldvalue = unit._properties[self.key] if oldvalue != value: with self.changing(oldvalue, value): unit._properties[self.key] = value def setting(self, unit, value): # begin code goes here yield None # end code goes here def changing(self, oldvalue, newvalue): # pre code goes here yield None # post code goes here ...(which would require macro-blocks which were decidedly *not* anonymous) then I could more cleanly write a subclass with additional macro methods: defmacro pre: old_children = self.children() defmacro post: for child in self.children: if child not in old_children: notify_somebody(New child %s % child) def changing(self, oldvalue, newvalue): old_children = self.children() yield None for child in self.children: if child not in old_children: notify_somebody(New child %s % child) Which do you prefer? I like fewer methods. ;-) Shane ___ 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
RE: [Python-Dev] defmacro (was: Anonymous blocks)
Shane Hathaway wrote: Robert Brewer wrote: So currently, all subclasses just override __set__, which leads to a *lot* of duplication of code. If I could write the base class' __set__ to call macros like this: def __set__(self, unit, value): self.begin() if self.coerce: value = self.coerce(unit, value) oldvalue = unit._properties[self.key] if oldvalue != value: self.pre() unit._properties[self.key] = value self.post() self.end() defmacro begin: pass defmacro pre: pass defmacro post: pass defmacro end: pass Here is a way to write that using anonymous blocks: def __set__(self, unit, value): with self.setting(unit, value): if self.coerce: value = self.coerce(unit, value) oldvalue = unit._properties[self.key] if oldvalue != value: with self.changing(oldvalue, value): unit._properties[self.key] = value def setting(self, unit, value): # begin code goes here yield None # end code goes here def changing(self, oldvalue, newvalue): # pre code goes here yield None # post code goes here ... Which do you prefer? I like fewer methods. ;-) I still prefer more methods, because my actual use-cases are more complicated. Your solution would work for the specific case I gave, but try factoring in: * A subclass which needs to share locals between begin and post, instead of pre and post. or * A set of 10 subclasses which need the same begin() but different end() code. Yielding seems both too restrictive and too inside-out to be readable, IMO. Robert Brewer MIS Amor Ministries [EMAIL PROTECTED] ___ 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
Re: [Python-Dev] defmacro (was: Anonymous blocks)
On 4/25/05, Guido van Rossum [EMAIL PROTECTED] wrote: It could also be done (though not as cleanly) by making macros act as import hooks. Brrr. What about imports that aren't at the top level (e.g. inside a function)? Bad style already. :D If you want to use the macro, you have to ensure it was already imported. That said, I did say it wasn't as clean; think of it like pre-caching which dictionary that resolved an attribute lookup. Don't start with the complexity, but consider not making the optimization impossible. Why not just introduce macros? Because I've been using Python for 15 years without needing them? And also without anonymous blocks or generator finalizers or resource managers. Sorry, but why not add feature X is exactly what we're trying to AVOID here. If anything is added, it might be better to add a single generalized tool instead of several special cases -- unless the tool is so general as to be hazardous. Unlimited macros are that hazardous. If the answer is We don't want xx sss (S\! 2k3 ] to ever be meaningful, then we need to figure out exactly what to prohibit. I don't understand what the point is of using an example like xx sss (S\! 2k3 ]. The simplest way to implement macros is to add an import hook that can modify (replace) the string containing the source code. Unfortunately, that would allow rules like replace any line starting with 'xx' with the number 7 Outside of obfuscators, almost no one would do something quite so painful as that ... but some people would start using regex substitutions or monkey-patching. I would hate to debug code that fails because a standard library module is secretly changed (on load, not on disk where I can grep for it) by another module, which doesn't even mention that library by name... As Michael said, we have to think about what transformations we do not want happening out of sight. I would have said Just use it responsibly if I hadn't considered pathological cases like that one. [yield works great for a single anonymous block, but not so great for several blocks per macro/template.] Pehaps you've missed some context here? Nobody seems to be able to come up with other [than resource wrappers] use cases, that's why yield is so attractive. Sorry; to me it seemed obvious that you would occasionally want to interleave the macro/template and the variable portion. Robert Brewer has since provided good examples at http://mail.python.org/pipermail/python-dev/2005-April/052923.html http://mail.python.org/pipermail/python-dev/2005-April/052924.html Or do we really just want a way to say that a function should share its local namespace with it's caller or callee? In that case, maybe the answer is a lexical or same_namespace keyword. Or maybe just a recipe to make exec or eval do the right thing. But should the same_namespace modifier be part of the call site or part of the callee? IMHO, it should be part of the calling site, because it is the calling site that could be surprised to find its own locals modified. The callee presumably runs through a complete call before it has a chance to be surprised. I did leave the decision open because I'm not certain that mention-in-caller wouldn't end up contorting a common code style. (It effectively forces the macro to be in control, and the meaningful code to be callbacks.) -jJ ___ 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
Re: [Python-Dev] defmacro (was: Anonymous blocks)
It seems that what you call macros is really an unlimited preprocessor. I'm even less interested in that topic than in macros, and I haven't seen anything here to change my mind. -- --Guido van Rossum (home page: http://www.python.org/~guido/) ___ 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
Re: [Python-Dev] defmacro (was: Anonymous blocks)
Robert Brewer wrote: I still prefer more methods, because my actual use-cases are more complicated. Your solution would work for the specific case I gave, but try factoring in: * A subclass which needs to share locals between begin and post, instead of pre and post. or * A set of 10 subclasses which need the same begin() but different end() code. Yielding seems both too restrictive and too inside-out to be readable, IMO. Ok, that makes sense. However, one of your examples seemingly pulls a name, 'old_children', out of nowhere. That's hard to fix. One of the greatest features of Python is the simple name scoping; we can't lose that. Shane ___ 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
Re: [Python-Dev] defmacro (was: Anonymous blocks)
Robert Brewer wrote: Shane Hathaway wrote: Robert Brewer wrote: So currently, all subclasses just override __set__, which leads to a *lot* of duplication of code. If I could write the base class' __set__ to call macros like this: def __set__(self, unit, value): self.begin() if self.coerce: value = self.coerce(unit, value) oldvalue = unit._properties[self.key] if oldvalue != value: self.pre() unit._properties[self.key] = value self.post() self.end() defmacro begin: pass defmacro pre: pass defmacro post: pass defmacro end: pass Here is a way to write that using anonymous blocks: def __set__(self, unit, value): with self.setting(unit, value): if self.coerce: value = self.coerce(unit, value) oldvalue = unit._properties[self.key] if oldvalue != value: with self.changing(oldvalue, value): unit._properties[self.key] = value def setting(self, unit, value): # begin code goes here yield None # end code goes here def changing(self, oldvalue, newvalue): # pre code goes here yield None # post code goes here ... Which do you prefer? I like fewer methods. ;-) I still prefer more methods, because my actual use-cases are more complicated. Your solution would work for the specific case I gave, but try factoring in: * A subclass which needs to share locals between begin and post, instead of pre and post. or * A set of 10 subclasses which need the same begin() but different end() code. Yielding seems both too restrictive and too inside-out to be readable, IMO. it seems what you are asking for are functions that are evaluated in namespace of the caller: - this seems fragile, the only safe wat to implement 'begin' etc is to exactly know what goes on in __set__ and what names are used there - if you throw in deferred evaluation for exprs or suites passed in as arguments and even without considering that, it seems pretty horrid implementation-wise Notice that even in Common Lisp you cannot really do this, you could define a macro that produce a definition for __set__ and takes fragments corresponding to begin ... etc ___ 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
[Python-Dev] defmacro (was: Anonymous blocks)
As best I can tell, the anonymous blocks are used to take care of boilerplate code without changing the scope -- exactly what macros are used for. The only difference I see is that in this case, the macros are limited to entire (possibly compound) statements. To make this more concrete, Guido: in synchronized(the_lock): BODY Nick Coghlan: s/in/with/ to get PEP 310. ... Guido's recent screed crystallised the idea of writing resources as two-part generators: ... [Adding Reinhold Birkenfeld's suggestion of a blank yield] def my_resource(): print Hi! # Do entrance code yield # Go on with the contents of the 'with' block print Bye!# Do exit code The macro itself looks reasonable -- so long as there is only ever one changing block inside the macro. I'm not sure that is a reasonable restriction, but the alternative is ugly enough that maybe passing around locals() starts to be just as good. What about a block that indicates the enclosed namespaces will collapse a level? defmacro myresource(filename): make explicit calls to named callback functions, but within the same locals() scope. with myresource(thefile): def reader(): ... def writer(): ... def fn(): Then myresource, reader, writer, and fn would share a namespace without having to manually pass it around. -jJ ___ 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