[pypy-dev] Re: "Unwrap" Concidered Harmful
arigo at tunes.org
Wed Sep 3 15:50:29 CEST 2003
On Tue, Sep 02, 2003 at 03:10:06PM +0100, Michael Hudson wrote:
> > * wrap(x) -> create a blackboxed reference for the interpreter object x
> > * unwrap(w_x,ExpectedType) -> inverse of the previous operation
> > * newint(i), newstr(s)... -> create simple object space objects
> (note this is like a bit like Py_BuildValue in the C API)
> I'd *much* rather write space.build(1) than space.newint(1).
Ok. Maybe the whole issue should be sorted out in the general context of how
to declare "gateways" between interpreter- and app-level. For example, given
an interpreter-level class
def __init__(self, frame):
self.w_stuff = space.newdict()
self.n = 5
self.frame = frame
def dosomething(self, w_x, i):
how could we cleanly specify that we want 'n' and 'dosomething' be
app-level-visible as, respectively, an integer object and a method taking two
arguments the second of which must be an integer? In other words the whole
Py_BuildValue / Py_BuildTuple / PyArg_ParseTuple business, plus
The point of giving the same name to wrap/unwrap and to the proposed
build/unbuild is to have a uniform way of exposing attributes of different
kinds, as shown on the above example:
* w_stuff is a wrapped app-level object all along, no conversion required.
* n is an integer, must use build/unbuild.
* frame is another interp-level internal object, must use wrap/unwrap.
This is the reason why we might want a single function pair for all three
cases. Alternatively we could use 'type descriptor' objects:
* t_wrapped.wrap(space, w_stuff) -> w_stuff
* t_int.wrap(space, 5) -> w_5
* t_interplevel.wrap(space, frame) -> wrapped frame
* t_wrapped.unwrap(space, w_stuff) -> w_stuff
* t_int.unwrap(space, w_5) -> 5
* t_interplevel.unwrap(space, w_frame) -> frame
The advantage is that we can declare function signatures explicitely, say
appmethod([t_wrapped, t_int], t_int) for the above dosomething() method, and
it is clear that the wrap/unwrap methods of the specified type descriptors
will be used for the conversion at appropriate times. (Type descriptors are
also a good place to store extra information and functionality if needed, e.g.
the corresponding C type. The idea comes from Thomas Heller's ctypes module.)
The t_xxx objects above could also be classes instead, with wrap/unwrap class
or static methods. This would let us use the interpreter-level class hierarchy
directly instead of the t_interplevel trick:
Frame.unwrap(space, w_frame) -> frame
This is more explicit because it can check that we actually have, not just an
interpreter-level object, but a Frame instance.
We could also put the space argument at the end, so that we can write
Frame.wrap(frame, space) -> w_frame
frame.wrap(space) -> w_frame
and thus wrap (but not unwrap) could actually be a regular method.
As a final note, there would then be a lot of different wrap/unwrap methods
defined all around which handle different types -- certainly a good thing for
flexibility and also for the annotation object space, which would not get
confused by the fact that a single build() or unwrap() could accept a whole
lot of different types.
More information about the Pypy-dev