
On Fri, 2011-10-14 at 10:01 +1000, Nick Coghlan wrote:
On Fri, Oct 14, 2011 at 7:01 AM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Withdrawing PEP 3150 altogether seems like an over- reaction to me. A lot of its problems would go away if the idea of trying to make the names local to the suite were dropped. That part doesn't seem particularly important to me -- we manage to live without the for-loop putting its variable into a local scope, even though it would be tidier if it did.
So, keep the PEP 3150 syntax, but don't make the inner suite special aside from the out of order execution?
While that would work, it still feels overly heavy for what I consider the primary use case of the construct:
sorted_list = sorted(original, key=key_func) given: def key_func(item): return item.attr1, item.attr2
The heart of the problem is that the name 'key_func' is repeated twice, encouraging short, cryptic throwaway names. Maybe I'm worrying too much about that, though - it really is the out of order execution that is needed in order to let the flow of the Python code match the way the developer is thinking about their problem.
Yes, you are worrying too much about this. :-) I like things that can be taken apart and put together again in a program and by a program. And even put together in new ways by a program. The special syntax and requirement that they be localized together doesn't fit that. Which means each time you want something similar to it, but with maybe with a small variation, you must rewrite the whole thing by hand. (Yes, we saved a few keystrokes each time, but...) To me that is going backwards and is a counter point to the purpose of programming. Hey lets keep those programmers working! JK ;-)
I'll note that the evolution from PEP 3150 (as shown above) to PEP 403 went as follows:
1. Make the inner suite a true anonymous function with the signature on the header line after the 'given' clause. Reference the function via '@' since it is otherwise inaccessible.
sorted_list = sorted(original, key=@) given (item): return item.attr1, item.attr2
2. Huh, that 'given' keyword doesn't scream 'anonymous function'. How about 'def' instead?
sorted_list = sorted(original, key=@) def (item): return item.attr1, item.attr2
3. Huh, that looks almost exactly like decorator prefix syntax. And the callable signature is way over on the RHS. What if we move it to the next line?
sorted_list = sorted(original, key=@) def (item): return item.attr1, item.attr2
4. We may as well let people add a name for debugging purposes, and it's less work to just make it compulsory to match existing syntax. By keeping the shorthand symbolic reference, we get the best of both worlds: a descriptive name for debugging purposes, a short local name for ease of use.
sorted_list = sorted(original, key=@) def key_func(item): return item.attr1, item.attr2
5. Well, the parser won't like that and it's backwards incompatible anyway. We need something to flag the prefix line as special. ':' will do.
:sorted_list = sorted(original, key=@) def key_func(item): return item.attr1, item.attr2
6. Keywords are better than symbols, so let's try that instead
postdef sorted_list = sorted(original, key=def) def key_func(item): return item.attr1, item.attr2
PEP 403 really is just an extension of the principles behind decorators at its heart, so I think it makes sense for those semantics to have a decorator-style syntax. If we want to revert back to using an indented suite, than I think it makes more sense to go all the way back to PEP 3150 and discuss the relative importance of "out of order execution" and "private scope to avoid namespace pollution".
Decorators can be moved out of the way and reused multiple times. I don't think this syntax can do that. It locks the two pieces together so they can't be used separately. Using your sort example. Lets say we rewrite that concept so it's more general using a decorator that can be reused. In this case, the key isn't the reusable part. It's the part that changes when we do sorts, so it's the part we put the decorator on to create a new sorted variation. def sorted_with(key): def _(seq): return sorted(seq, key=key) return _ @sorted_with def key_sorted(item): return item.attr1, item.attr2 new_list = key_sorted(original_list) We can reuse the sorted_with decorator with as may key functions as we want. That reuse is an important feature of decorators. Cheers, Ron