Permalink
Cannot retrieve contributors at this time
242 lines (174 sloc)
8.37 KB
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| PEP: 3117 | |
| Title: Postfix type declarations | |
| Version: $Revision$ | |
| Last-Modified: $Date$ | |
| Author: Georg Brandl <georg@python.org> | |
| Status: Rejected | |
| Type: Standards Track | |
| Content-Type: text/x-rst | |
| Created: 01-Apr-2007 | |
| Python-Version: 3.0 | |
| Post-History: | |
| Abstract | |
| ======== | |
| This PEP proposes the addition of a postfix type declaration syntax to | |
| Python. It also specifies a new ``typedef`` statement which is used to create | |
| new mappings between types and declarators. | |
| Its acceptance will greatly enhance the Python user experience as well as | |
| eliminate one of the warts that deter users of other programming languages from | |
| switching to Python. | |
| Rationale | |
| ========= | |
| Python has long suffered from the lack of explicit type declarations. Being one | |
| of the few aspects in which the language deviates from its Zen, this wart has | |
| sparked many a discussion between Python heretics and members of the PSU (for | |
| a few examples, see [EX1]_, [EX2]_ or [EX3]_), and it also made it a large-scale | |
| enterprise success unlikely. | |
| However, if one wants to put an end to this misery, a decent Pythonic syntax | |
| must be found. In almost all languages that have them, type declarations lack | |
| this quality: they are verbose, often needing *multiple words* for a single | |
| type, or they are hard to comprehend (e.g., a certain language uses completely | |
| unrelated [#]_ adjectives like ``dim`` for type declaration). | |
| Therefore, this PEP combines the move to type declarations with another bold | |
| move that will once again prove that Python is not only future-proof but | |
| future-embracing: the introduction of Unicode characters as an integral | |
| constituent of source code. | |
| Unicode makes it possible to express much more with much less characters, which | |
| is in accordance with the :pep:`Zen <20>` ("Readability counts."). Additionally, it | |
| eliminates the need for a separate type declaration statement, and last but not | |
| least, it makes Python measure up to Perl 6, which already uses Unicode for its | |
| operators. [#]_ | |
| Specification | |
| ============= | |
| When the type declaration mode is in operation, the grammar is changed so that | |
| each ``NAME`` must consist of two parts: a name and a type declarator, which is | |
| exactly one Unicode character. | |
| The declarator uniquely specifies the type of the name, and if it occurs on the | |
| left hand side of an expression, this type is enforced: an ``InquisitionError`` | |
| exception is raised if the returned type doesn't match the declared type. [#]_ | |
| Also, function call result types have to be specified. If the result of the call | |
| does not have the declared type, an ``InquisitionError`` is raised. Caution: the | |
| declarator for the result should not be confused with the declarator for the | |
| function object (see the example below). | |
| Type declarators after names that are only read, not assigned to, are not strictly | |
| necessary but enforced anyway (see the Python Zen: "Explicit is better than | |
| implicit."). | |
| The mapping between types and declarators is not static. It can be completely | |
| customized by the programmer, but for convenience there are some predefined | |
| mappings for some built-in types: | |
| ========================= =================================================== | |
| Type Declarator | |
| ========================= =================================================== | |
| ``object`` � (REPLACEMENT CHARACTER) | |
| ``int`` ℕ (DOUBLE-STRUCK CAPITAL N) | |
| ``float`` ℮ (ESTIMATED SYMBOL) | |
| ``bool`` ✓ (CHECK MARK) | |
| ``complex`` ℂ (DOUBLE-STRUCK CAPITAL C) | |
| ``str`` ✎ (LOWER RIGHT PENCIL) | |
| ``unicode`` ✒ (BLACK NIB) | |
| ``tuple`` ⒯ (PARENTHESIZED LATIN SMALL LETTER T) | |
| ``list`` ♨ (HOT SPRINGS) | |
| ``dict`` ⧟ (DOUBLE-ENDED MULTIMAP) | |
| ``set`` ∅ (EMPTY SET) (*Note:* this is also for full sets) | |
| ``frozenset`` ☃ (SNOWMAN) | |
| ``datetime`` ⌚ (WATCH) | |
| ``function`` ƛ (LATIN SMALL LETTER LAMBDA WITH STROKE) | |
| ``generator`` ⚛ (ATOM SYMBOL) | |
| ``Exception`` ⌁ (ELECTRIC ARROW) | |
| ========================= =================================================== | |
| The declarator for the ``None`` type is a zero-width space. | |
| These characters should be obvious and easy to remember and type for every | |
| programmer. | |
| Unicode replacement units | |
| ========================= | |
| Since even in our modern, globalized world there are still some old-fashioned | |
| rebels who can't or don't want to use Unicode in their source code, and since | |
| Python is a forgiving language, a fallback is provided for those: | |
| Instead of the single Unicode character, they can type ``name${UNICODE NAME OF | |
| THE DECLARATOR}$``. For example, these two function definitions are equivalent:: | |
| def fooƛ(xℂ): | |
| return None | |
| and :: | |
| def foo${LATIN SMALL LETTER LAMBDA WITH STROKE}$(x${DOUBLE-STRUCK CAPITAL C}$): | |
| return None${ZERO WIDTH NO-BREAK SPACE}$ | |
| This is still easy to read and makes the full power of type-annotated Python | |
| available to ASCII believers. | |
| The ``typedef`` statement | |
| ========================= | |
| The mapping between types and declarators can be extended with this new statement. | |
| The syntax is as follows:: | |
| typedef_stmt ::= "typedef" expr DECLARATOR | |
| where ``expr`` resolves to a type object. For convenience, the ``typedef`` statement | |
| can also be mixed with the ``class`` statement for new classes, like so:: | |
| typedef class Foo☺(object�): | |
| pass | |
| Example | |
| ======= | |
| This is the standard ``os.path.normpath`` function, converted to type declaration | |
| syntax:: | |
| def normpathƛ(path✎)✎: | |
| """Normalize path, eliminating double slashes, etc.""" | |
| if path✎ == '': | |
| return '.' | |
| initial_slashes✓ = path✎.startswithƛ('/')✓ | |
| # POSIX allows one or two initial slashes, but treats three or more | |
| # as single slash. | |
| if (initial_slashes✓ and | |
| path✎.startswithƛ('//')✓ and not path✎.startswithƛ('///')✓)✓: | |
| initial_slashesℕ = 2 | |
| comps♨ = path✎.splitƛ('/')♨ | |
| new_comps♨ = []♨ | |
| for comp✎ in comps♨: | |
| if comp✎ in ('', '.')⒯: | |
| continue | |
| if (comp✎ != '..' or (not initial_slashesℕ and not new_comps♨)✓ or | |
| (new_comps♨ and new_comps♨[-1]✎ == '..')✓)✓: | |
| new_comps♨.appendƛ(comp✎) | |
| elif new_comps♨: | |
| new_comps♨.popƛ()✎ | |
| comps♨ = new_comps♨ | |
| path✎ = '/'.join(comps♨)✎ | |
| if initial_slashesℕ: | |
| path✎ = '/'*initial_slashesℕ + path✎ | |
| return path✎ or '.' | |
| As you can clearly see, the type declarations add expressiveness, while at the | |
| same time they make the code look much more professional. | |
| Compatibility issues | |
| ==================== | |
| To enable type declaration mode, one has to write:: | |
| from __future__ import type_declarations | |
| which enables Unicode parsing of the source [#]_, makes ``typedef`` a keyword | |
| and enforces correct types for all assignments and function calls. | |
| Rejection | |
| ========= | |
| After careful considering, much soul-searching, gnashing of teeth and rending | |
| of garments, it has been decided to reject this PEP. | |
| References | |
| ========== | |
| .. [EX1] https://mail.python.org/pipermail/python-list/2003-June/210588.html | |
| .. [EX2] https://mail.python.org/pipermail/python-list/2000-May/034685.html | |
| .. [EX3] http://groups.google.com/group/comp.lang.python/browse_frm/thread/6ae8c6add913635a/de40d4ffe9bd4304?lnk=gst&q=type+declarations&rnum=6 | |
| .. [#] Though, if you know the language in question, it may not be *that* unrelated. | |
| .. [#] Well, it would, if there was a Perl 6. | |
| .. [#] Since the name ``TypeError`` is already in use, this name has been chosen | |
| for obvious reasons. | |
| .. [#] The encoding in which the code is written is read from a standard coding | |
| cookie. There will also be an autodetection mechanism, invoked by ``from | |
| __future__ import encoding_hell``. | |
| Acknowledgements | |
| ================ | |
| Many thanks go to Armin Ronacher, Alexander Schremmer and Marek Kubica who helped | |
| find the most suitable and mnemonic declarator for built-in types. | |
| Thanks also to the Unicode Consortium for including all those useful characters | |
| in the Unicode standard. | |
| Copyright | |
| ========= | |
| This document has been placed in the public domain. | |
| .. | |
| Local Variables: | |
| coding: utf-8 | |
| mode: indented-text | |
| indent-tabs-mode: nil | |
| sentence-end-double-space: t | |
| fill-column: 70 | |
| End: |