[Python-ideas] pep-0484 - Forward references and Didactics - be orthogonal

Stephen J. Turnbull stephen at xemacs.org
Wed Aug 26 04:14:35 CEST 2015


Prof. Dr. L. Humbert writes:

 > 1st class pedagogical/didactical thinking …
 > Consider: there are recursive defined ADTs and we want to enable
 > students to understand concepts and produce python-code to realize, what
 > they understood.

I think we all understand your point.

The problem is that Python as designed is simply not capable of that.
You have a choice: python-code with its "class statements bind names
to (fully-constructed) class objects" semantics, or pseudo-python with
"class statements are declarations" semantics.  Python simply isn't a
declarative language in that sense.

I don't have any objection to a language with different semantics, but
I find Python's semantics very consistent (except for module import --
which is improved a lot thanks to Brett -- and the occasional class
which creates attributes in __getattr__ -- which I dislike for this
reason).  I doubt Python-Dev will want to give up that consistency; I
know I don't want to.

Although the PEP doesn't explicitly say it's a good practice, AFAICS
using the name of a type (ie, a string) is supported everywhere a type
identifier is.  (Explicitly permitted are *forward* references to
*undefined* types.  However, in the "Django" example where "A.a" is
the name of a type defined in module A, "B.b" is defined in B, and
each uses the other, in

    import A
    import B        # refers to A.a using the string "A.a"

A.a is an existing type.  I conclude that unless the implementation is
excessively complicated, it's permitted to refer to already defined
types using the string name.)

In other words, although

class Leaf():
    def __init__(self, value: int):
        self.value = value

class Tree:                                # with leaves
    def __init__(self, left: Union['Tree', Leaf], right: Union['Tree', Leaf]):
        self.left = left
        self.right = right

is indeed non-orthogonal and ugly, you could declare the constructors

    def __init__(self, value: 'int'):
    def __init__(self, left: 'Union[Tree, Leaf]', right: 'Union[Tree, Leaf]'):

using actual names of types (strings like "'Tree'") instead of bound
names (identifiers like "Tree") everywhere.  That may not be quite as
clean as you'd like, but it seems orthogonal enough to me: you have a
consistent syntax for all type annotations.

I'd also point out that your own notation isn't quite orthogonal: self
isn't annotated in your method definitions.  If students can handle
the special syntax for "self", I suppose that they can handle a
special syntax for recursively defined types (or you could use Steven
d'A's approach of a placeholder class "RecursivelyDefined", which
would require augmenting the typechecker to recognize it).

Steve



More information about the Python-ideas mailing list