[pypy-dev] Objects and types in the stdobjspace

Armin Rigo arigo at tunes.org
Tue Jun 10 14:13:23 CEST 2003


Hello Holger,

On Tue, Jun 10, 2003 at 12:02:55AM +0200, holger krekel wrote:
> If we would restrict ourself to just one possible implementation of a
> type then it wouldn't be neccesary to have a W_XxxObject for each type
> but the implementation methods could be directly on the Type object? 

Well, the implementation can only be on the actual class implementing the 
object, and that is W_XxxObject. The W_XxxType class looks like a hack to me 
at the moment. I think I would prefer another way to declare types, e.g. using 
the module globals directly instead of a class with a single instance.

In this scheme the xxxtype module would be the "declaration" of the type,
whereas the xxxobject module(s) would contain the class(es) implementing it.  
If we really don't want to separate them then they could probably both be in a
single module, sure. Now whether you call this module xxxobject or xxxtype is
unclear. I think that systematically separate type with implementation is a
good idea anyway.

> I am wondering if this design comes from your psyco experience. IIRC
> PSYCO improves the common "string+=something" cases by doing the 
> list/append dance internally. Which model does PSYCO use to do this
> compared to the PyPy-approach? 

Yes, it is clearly related. Psyco uses alternate implementations internally,
e.g. for the "string+=string". Whenever I need a real CPython object to be
built however I must revert back to the standard implementation, of course. I
see something similar to be possible between PyPy and CPython-compatible
extension modules: PyPy can use whatever implementation it likes for the
objects, but as soon as one object can be seen by an extension module then it
must revert to the standard CPython-like PyObject.

> > >     def type_repr(space, w_obj):
> > >         return space.wrap("<type '%s'>" % w_obj.typename)
> 
> Any reason not name it "__name__" instead of "typename"?

Because "__name__" has a special meaning in Python classes; we expect it to be
"W_TypeObject", i.e. the name of w_obj.__class__. We could name it "tp_name"  
or anything else, but I guess "__name__" is just a bad choice (just like the
addition between wrapped objects is not "__add__" but "space.add").

> > There is no way to dispatch a multimethod based on the type of an argument,
> 
> But this could be emulated by registering all implementations of a type,
> couldn't it?

No piece of code should expect it knows all possible implementations of a
type. If this were needed, a more declarative way would be better.

> And if you register the signature 
> 
>     (W_StringObject, W_ANY)
> 
> and the signature 
> 
>     (W_ANY, W_StringObject)
> 
> for a "MultiMethod" which one gets selected? 

The rules are not "official" yet because we'll see in practice if that needs
refinement. In general they are left-to-right, yes, so an exact match for the
first argument always wins.

> I'd have thought that the "unbound methods rule" is more a restriction
> rooting in the dependence of a python method on its "fixed" data structure of 
> the object. If so, wouldn't it be more pythonic to avoid LBYL (Look
> before you leap) style of restrictions?

What Samuele and I had in mind would be to somehow tie the implementations to 
the object types they are expected to work with. We wanted to emulate 
Python's behavior of:

  1 .__add__(1.0)  -> NotImplemented
  1.0 .__add__(1)  -> 2.0

which is somehow reasonable, given that we have defined the following two
implementations: 'int+int' and 'float+float'. The second one should not be
available to 'int.__add__' because it requires the bound argument to be
converted ("delegated") to float, and 'int.__add__(1.0,1.0)' is certainly no
Python code that we'd like to see succeed.

> (trying hard to avoid to get picky about names but failing ...) why
> not use plain W_Object? W_ANY sounds like CORBA to me :-)

We came up with the equivalence 'W_ANY is W_Object' later on the sprint. They
used to be different things. I have a future redesign on the back of my head
that would change (and reduce) a lot of this boilerplate code, and which would
probably replace 'W_ANY' with 'object' actually. More about it in some later
e-mail.

> > def any_list_extend(space, w_list, w_otherlist):
> >     return space.inplace_add(w_list, w_otherlist)
> > 
> > W_ListType.list_extend.register(any_list_extend, W_ANY, W_ANY)

Not sure how to reduce this, however. I am not too fond of name-based magic.  
Function attributes would be handy but there is no nice way to define them
before the body of the function. Docstring-based hacks are bad bad bad. And
the following has already been (justifiably) rejected as not good-looking and
requiring quite some metaclass hacks:

class __magic__(W_ANY, W_ANY):
    def list_extend(space, w_list, w_otherlist):
        return space.inplace_add(w_list, w_otherlist)

One more (really magic too) alternative I could think of is

def any_list_extend(space, w_list, w_otherlist, __impl__=(W_ANY, W_ANY)):
    return space.inplace_add(w_list, w_otherlist)

Well, while we are at it, really magic things can happend and make this work:

def any_list_extend(space, w_list, w_otherlist):
    withinstance(w_list, W_ANY)
    withinstance(w_otherlist, W_ANY)
    return space.inplace_add(w_list, w_otherlist)

or

def any_list_extend(space, w_list, w_otherlist):
    implementing(W_ListType.list_extend, W_ANY, W_ANY)
    return space.inplace_add(w_list, w_otherlist)

Does it look like we are about to reinvent a type declaration system for
Python ?


A bientôt,

Armin.


More information about the Pypy-dev mailing list