I just found a document I wrote back in 2007 about the, then proposed, Python3000 project. This later became Python 3.0. I thought it might be amusing to re-print it here. Some of the musings in there later found its way into python albeit much later.
I may have posted this to python-dev at the time, or just left it in my outbox. I can’t remember. At the time, I had become a bit frustrated with the way things were being run in the organization so I may have not communicated this at all.
So, here is the stuff: Enjoy.
Issues and points about Python 3000
We at CCP think it is important to use the breaking change that is Python 3000 to do some more radical reforms, which otherwise are probably not going to happen ever. Since things are changing anyway, why not change them a bit more and make everything better?
- C API is inconsistent. Need to adapt a consistency, such as always returning a new reference by indirection (borrow idea from COM)
//create a new integer. A new object returned in *result
bool PyInt_FromLong(PyObject **result, long value);
//look up stuff in the dict. Return a borrowed reference
PyObject *PyDict_GetItem(PyObject *key);- Python3000 Should really move into C99 (or even C++?) land. After all, platforms are being dropped and every one should provide C99 support (gcc3.0 and beyond). What I want so see is not class-based implementation of Python, but rather language features such as:
- the inline keyword. Get rid of macros where they aren’t needed (C99)
- in-code declaration of variables (C99).
- the bool keyword (C99)
- Possibly use std c++ library features where useful, such as for strings/unicode and some basic STL containers (C++).
- There are toolkits like Boost.python and swig for making it easier to build C extensions. Why doesn’t python do such things itself for builtin types, to reduce the size of the code and increase reliability? Why are such layers needed in the first place?
- It should be easier to inject custom memory handlers into python. Currently this is a nightmare because of the three different memory APIs used (object alloc, malloc, pymalloc). This would be made much easier using inline functions, see above.
- Too often Exceptions are used for control flow. Even in the C api. For example, the PyObject_HasAttr() API is implemented through a PyObject_GetAttr() which then clears the generated exception. Creating these exceptions is expensive. The PyObject_HasAttr() should really be implemented properly as a query function which optionally can raise an exception:
//look up an attribute. If "hard" is false, no exception is raised if it is not found.
bool PyObject_GetAttr(PyObject **result, PyObject *object, PyObject *attrib, bool hard);- (Possibly already addressed?) Fix exception handling semantics. Python has no idea of being “in an exception handling context.” Therefore, the exception last caught sits in the TLS even after it has been handled. Exception handling context should be separately stackable. When one is executing the exception handler for exception A, that exception is current. We can then raise and catch a different exception during the handling of A, say B. We can handle B, then after that except: clause, B is popped and we get back to handling A. When exiting the except: clause for A, A is popped an no exception is current. This achieves two things:
- the exception A doesn’t linger within the interpreter any longer than necessary, keeping huge resources and stack frames alive.
- It is possible to query the language if it is in an exception handling context. The presence of a current exception would indicate this.
- We want to help guide Python 3000 to be future safe. Make a sensible api. Think about threads. Think about C++ and boost. Think about hard/soft stack switching and IO.
- Make the API so that the code inherently uses a C stack free internal implementation. Just an execution engine. Stackless.
- consider using Boost python, or conversely, make Boost benefit from Python. This might mean that the whole thing ought to be written in C++ anyway. At the very least, consult with the maker of Boost Python. Currently too much boilerplate in the implementation of Python and also when creating extensions and types – repeating the same macros over and over is not fun.
- The point is, soft switching could be a step to unify generators/co-routines in Python with stackless. Why not use the same kind of continuation-like mechanism for both?
- Hard switching is needed to do tricks from C code. This is why you can’t write a generator function in C
- Multi threading! All the processor growth the next few years will be horizontal, with added cpus. To leverage that, games have to be more and more threaded. Several areas of Python don’t jive with threading:
- Reference counting (atomic lock-and-increment could help)
- global constructs such as the linked list of objects, which brings us to:
- garbage collection.
- Various modules have their own nifty little recycling mechanism for objecst, such as string, tuple, int, etc etc. They maintain lists of empty objects for usage and these are not threadsafe.
- The interpreter has a GIL. Maybe it is okay, but lots of stuff in python can have the side effect of running python code.
- We are mainly thinking about parallelizing stuff from the C API side.
- Worker threads need to be able to manipulate python constructs, and create python constructs for consumption of other threads.