[pypy-dev] Objects and types in the stdobjspace

Armin Rigo arigo at tunes.org
Thu Jun 5 17:32:59 CEST 2003


Hello everybody,

Here is a technical note for the way Samuele and I implemented objects and
types based on multimethods.

In objspace/std/ you will find for each type xxx two files: xxxobject.py and
xxxtype.py. The former defines a class W_XxxObject. Each instance of
W_XxxObject is seen by the user (i.e. the person using the language, i.e.
application-level) as an object of type xxx. The xxxtype.py file, on the other
hand, defines a class W_XxxType, which is expected to have exactly one
instance, which is what the user sees as the xxx type object (e.g. the single
instance of W_IntType is what the user sees as 'types.IntType' or 'int').

The same applies to the type 'object': it has a objectobject.py file defining
the class W_ObjectObject, whose instances are the direct instances of
'object', i.e. what the user can have by writing 'object()'. These are pretty
featureless. There is also objecttype.py with the class W_ObjectType whose
single instance is seen as 'object', the type.

The same for type objects: the file typeobject.py defines the class
W_TypeObject, whose instances are types. That's why all other W_XxxType
classes actually inherit (at interpreter-level) from W_TypeObject. And there
is W_TypeType in typetype.py whose single instance is the 'type' type.

The situation for user-defined types and instances of these types is more
problematic. Right now, all user-defined type object are instances of
W_UserType, found in usertype.py, and instances of these user-defined types
are instances of W_UserObject from userobject.py. Application-level
inheritance is not visible at all as inheritance among these interpreter-level
classes; there is some look-up mecanism in W_TypeObject that is responsible
for emulating it. (This is necessary, otherwise we would be stealing the 
underlying inheritance mecanism of CPython, which is not what we want to do 
for user-defined types with possibly multiple inheritance and method 
resolution orders that depend on the CPython version!).

There is a problem, however, which is related to how we hack to let a
W_UserObject pass for some other W_XxxObject class for some other parts of the
stdobjspace.  Try for example:

>>> class specialtype(type):
...   pass
... 
>>> specialtype('L', (list,), {})
<specialtype object at 138362900>
>>> L = _
>>> L([1,2,3])
  File ".../userobject.py", line 51, in getsinglebuiltintype
    mro = list(w_type.getmro())
AttributeError: W_UserObject instance has no attribute 'getmro'

(I'm going to try to fix this right now.) This is because w_type contains the
'L' object, which the interpreter expects to be a W_TypeObject, but which is
actually a W_UserObject because it is an instance of the W_UserType named
'specialtype'.

We'll have to sort this out, and a proper solution probably means starting
with the following: in CPython, if say C inherits from the built-in class D,
then instances of C are implemented as a structure which starts with the same
fields as a D structure. This is so that the PyObject* pointer can pass for a
pointer to the structure can pass for a pointer to a C or a D object, for the
interpreter. In PyPy, we can emulate this behavior in W_UserObject: an
instance of W_UserObject could pass for an instance of some other
dynamically-determined W_XxxObject using some __getattr__ hacks. This can be
written in such a way that it is RPython-friendly, so that the C translator
knows that it is expected to produce compatible structure layouts and do
pointer typecasts.

Interestingly, we could also later add other implementations of W_UserType 
that don't suffer from this restriction.


A bientôt,

Armin.


More information about the Pypy-dev mailing list