[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