> I'm really curious what these uses might be. Folks keep saying this > kind of thing, but when you dig in IMHO most of these > actually seem to > be design-time things, statements *about* the intent or use of the > function (relative to the language runtime itself, e.g. > classmethod and > so forth, or relative to a framework, such as registering a function, > or relative to some tool, e.g. for extended documentation purposes or > type-checking, etc.) rather than e.g. runtime modifications to its > behavior. Well, perhaps you and I mean slightly different things when we talk about "declarative" functionality. Here are some uses, you let me know whether they are "declarative" or not: 1. Registering with a framework: [FooFramework] def some_func(): body() FooFramework() "registers" the function with a framework by simply adding it to a list of known functions. This allows the GUI interface for FooFramework to display the function. 2. Take actions before or after a call: [traceable] def some_func(): body() traceable() replaces some_func() with a function which may write a log message before and after actually invoking the original some_func(). Whether the log message is actually written is controlled by a list of function names (compared to some_func.__name__) and that list may change dynamically while the program is executing. 3. Enforce pre- and post- conditions: [precondition(lambda x,y: x<y), postcondition(lambda x,y,result: x<result<y)] def some_func(x, y): body() precondition() and postcondition() document what we expect to be true before and after a function is invoked. Furthermore, if the constant Contract.PROD in the Contract module is False, then they replace some_func() with a wrapped version which tests the conditions and raises a ContractException if they fail. (Note: I don't think this is the best design for a design-by-contract library, just one approach which I think decorators SHOULD make possible.) 4. Storing Private Data: class Some_Class: [private] def some_method(self, private, x): body(self, private, x) This is kind of far out, but private() replaces the function some_method(self,private,x) with a wrapper function some_method(self,x) which takes just TWO arguments. Then the original some_method() is invoked with all three arguments, including "private" which is a dict that the wrapper conjures up from someplace well hidden. This means that the method some_method() can have access to the values in the "private" dict (and can write values into it also), but someone inspecting the __dict__ of the Some_Class instance won't be able to find (or change) "private". There are lots of other good ideas out there (many better than these), but I'm wondering whether you consider these to be "declarative". You follow with a few questions: > (1) Does a function have access to its own decorators? I wouldn't think so. They are NOT "metadata", that's just one possible use. The function no more has access to its decorators than it has access to its source code! If we just needed a place to stick metadata we'd use the function's __dict__. > (2) Do decorators define literal constant values at > design-time or do > they define a scope of mutable bindings? The decorators are simply functions that get executed. > x = "Guido van Rossum" > def mymethod(f) [attrs(versionadded="2.2", author=x)]: That's fine. author is set to Guido. > x = "Guido van Rossum" > def mymethod(f) [attrs(versionadded="2.2", author=x)]: > oldAuthor = someHandleToMyDecorators.atts.author > someHandleToMyDecorators.atts.author = "Eric Idle" That's meaningless unless I know what "someHandleToMyDecorators" means. > IMHO, the RHS of an "assignment" in a decorator should only be some > value that can be known at "compile" time I disagree. I think you and I just have different ideas about what we'd use decorators for. (Actually, I think that perhaps your set of intended uses is a subset of mine.) > (3) Should it be possible to conditionally evaluate decorators based > on run-time state? > > The following, IMHO, is truly scary and inhibits many of the intended > uses of decorators. This shouldn't be legal, ever: > > if foo = 3: > [someDecoratorThatModifiesBarsRuntimeBehavior] > else: > [someOtherDecorator] > def bar(...): > ... Hmm... I hadn't considered that one. I'll reserve judgment. I wouldn't mind if it worked, but I'd certainly try never to use it. I *WOULD* however make use of things like this: if foo = 3: standard_decoration = someDecoratorWithALongName else: standard_decoration = someOtherDecorator # ... [standard_decoration] def bar(...): ... You write "The following, IMHO, is truly scary and inhibits many of the intended uses of decorators". I'm not sure that intended uses it is inhibiting. The only one I can imagine is using decorators to create a type-aware compiler that generates type- specific optimized code. I don't think this IS a possible use for decorators. So... what use *would* be inhibited if decorators were used in this manner? -- Michael Chermside This email may contain confidential or privileged information. If you believe you have received the message in error, please notify the sender and delete the message without copying or disclosing it.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4