[Python-checkins] peps: Expand the discussion of nested suite variants
nick.coghlan
python-checkins at python.org
Tue Sep 4 13:33:51 CEST 2012
http://hg.python.org/peps/rev/5377635cedcd
changeset: 4506:5377635cedcd
user: Nick Coghlan <ncoghlan at gmail.com>
date: Tue Sep 04 21:33:39 2012 +1000
summary:
Expand the discussion of nested suite variants
files:
pep-0403.txt | 167 +++++++++++++++++++++++++++++++-------
1 files changed, 137 insertions(+), 30 deletions(-)
diff --git a/pep-0403.txt b/pep-0403.txt
--- a/pep-0403.txt
+++ b/pep-0403.txt
@@ -216,27 +216,6 @@
actual name binding in the current scope.
-Why not a nested suite?
------------------------
-
-The problem with using a full nested suite is best described by reviewing
-PEP 3150. It's ridiculously hard to implement properly, and creates way
-too many situations where there are two ways to do it (almost any construct
-that can be expressed with ordinary imperative code could instead be
-expressed using a given statement).
-
-By contrast, the decorator inspired syntax explicitly limits the new
-feature to cases where it should actually improve readability, rather than
-harming it. As in the case of the original introduction of decorators, the
-idea of this new syntax is that if it *can* be used (i.e. the local name
-binding of the function is completely unnecessary) then it *should* be used.
-
-While a non-decorator based alternative could be considered (e.g. a nested
-"suite" that actually allowed only a single class or function definition),
-it seems excessive to introduce a completely new concept when it is
-possible to use a variant of the existing decorator syntax instead.
-
-
Keyword Choice
--------------
@@ -300,7 +279,9 @@
The one potentially tricky part is changing the meaning of the references to
the statement local function or namespace while within the scope of the
``in`` statement, but that shouldn't be too hard to address by maintaining
-some additional state within the compiler.
+some additional state within the compiler (it's much easier to handle this
+for a single name than it is for an unknown number of names in a full
+nested suite).
More Examples
@@ -383,9 +364,32 @@
Rejected Concepts
=================
-A previous incarnation of this PEP (see [1]) proposed a much uglier syntax
-that (quite rightly) was not well received. The current proposal is
-significantly easier both to read and write.
+To avoid retreading previously covered ground, some rejected alternatives
+are documented in this section.
+
+
+Omitting the decorator prefix character
+---------------------------------------
+
+Earlier versions of this proposal omitted the ``@`` prefix. However, without
+that prefix, the bare ``in`` keyword didn't associate the clause strongly
+enough with the subsequent function or class definition. Reusing the
+decorator prefix and explicitly characterising the new construct as a kind
+of decorator clause is intended to help users link the two concepts and
+see them as two variants of the same idea.
+
+
+Anonymous Forward References
+----------------------------
+
+A previous incarnation of this PEP (see [1]) proposed a syntax where the
+new clause was introduced with ``:`` and the forward reference was written
+using ``@``. Feedback on this variant was almost universally
+negative, as it was considered both ugly and excessively magical::
+
+ :x = weakref.ref(target, @)
+ def report_destruction(obj):
+ print("{} is being destroyed".format(obj))
A more recent variant always used ``...`` for forward references, along
with genuinely anonymous function and class definitions. However, this
@@ -403,11 +407,114 @@
a = calculate_a()
b = calculate_b()
-Another past alternative omitted the ``@`` prefix. However, without that
-prefix, the bare ``in`` keyword didn't associate the clause strongly
-enough with the subsequent function or class definition. Reusing the
-decorator prefix and explicitly characterising the new construct as a kind
-of decorator clause should address that problem.
+
+Using a nested suite
+--------------------
+
+The problems with using a full nested suite are best described in
+PEP 3150. It's comparatively difficult to implement properly, the scoping
+semantics are hard to explain and it creates quite a few situations where
+there are two ways to do it without clear guidelines for choosing between
+them (as almost any construct that can be expressed with ordinary imperative
+code could instead be expressed using a given statement). While the PEP did
+propose some new PEP 8 guidelines to help address that last problem, the
+difficulties in implementation and explanation are not so easily dealt with.
+
+By contrast, the decorator inspired syntax in this PEP explicitly limits the
+new feature to cases where it should actually improve readability, rather
+than harming it. As in the case of the original introduction of decorators,
+the idea of this new syntax is that if it *can* be used (i.e. the local name
+binding of the function is completely unnecessary) then it *should* be used.
+
+Another possible variant of this idea is to keep the decorator based
+*semantics* of this PEP, while adopting the prettier syntax from PEP 3150::
+
+ x = weakref.ref(target, report_destruction) given:
+ def report_destruction(obj):
+ print("{} is being destroyed".format(obj))
+
+There are a couple of problems with this approach. The main issue is that
+this syntax variant uses something that looks like a suite, but really isn't
+one. A secondary concern is that it's not clear how the compiler will know
+which name(s) in the leading expression are forward references (although
+that could potentially be addressed through a suitable definition of the
+suite-that-is-not-a-suite in the languge grammar).
+
+There's yet another possibility which would require names to be explicitly
+lifted out of the private namespace, eliminating much of the implementation
+complexity discussed in PEP 3150 (as only identifiers would be exported,
+rather than arbitrary subexpressions)::
+
+ x = weakref.ref(target, report_destruction) given report_destruction from:
+ def report_destruction(obj):
+ print("{} is being destroyed".format(obj))
+
+or even::
+
+ x = weakref.ref(target, f) given report_destruction as f from:
+ def report_destruction(obj):
+ print("{} is being destroyed".format(obj))
+
+This approach actually has much to recommend it. It's as powerful as
+PEP 3150 while being substantially simpler both to implement and to
+explain. The main downside is that it requires even *more* repetition
+of names than is needed with the proposed ``@in`` decorator based syntax
+or with the status quo where the function is defined and bound to a local
+name prior to its sole use.
+
+Some more examples using this last variant::
+
+ sorted_list = sorted(original, key=f) given f from:
+ def f(item):
+ try:
+ return item.calc_sort_order()
+ except NotSortableError:
+ return float('inf')
+
+ funcs = [adder(i) for i in range(10)] given adder from:
+ def adder(i):
+ return lambda x: x + i
+
+ environ = _createenviron() given _createenviron from:
+ def _createenviron():
+ ... # 27 line function
+
+ c = math.sqrt(a*a + b*b) given a, b from:
+ a = calculate_a()
+ b = calculate_b()
+
+ dispatch[MyClass] = f given f from:
+ def f():
+ ...
+
+ f() given f from:
+ def f():
+ ...
+
+One interesting outcome of such an approach is that it allows the semantics
+of function decoration to be represented almost exactly as a specific
+case of the new syntax::
+
+ # @deco2
+ # @deco1
+ # def name():
+ # ...
+
+ name = f given f from:
+ # Decorator expressions are evaluated first, in code order
+ _d2 = deco2
+ _d1 = deco1
+
+ # The base function object is defined
+ def name():
+ ...
+
+ # Decorators are applied innermost first
+ f = _d2(_d1(name))
+
+Hmm, perhaps PEP 3150 isn't *quite* as dead as I thought, although the
+triple repetition of names is still a rather large downside.
+
References
==========
--
Repository URL: http://hg.python.org/peps
More information about the Python-checkins
mailing list