
Armin Rigo <arigo@tunes.org> wrote:
On Sat, Aug 23, 2003 at 09:00:58PM -0400, Rocco Moretti wrote:
all information about value. So there is no way we can say that s.unwrap(s.wrap(x)) == x.
I am now coming closer to the idea that wrap() should be redefined as well, because it is used not only on simple types but also on "internal interpreter structures", like code objects plus others more internals than that.
Let me see if I can clarify my present understanding. (Thinking out loud follows...) When we use wrap(x), we mean one of two things: 1) Give me an application level object that is equivalent to x. 2) Make the interpreter level object x available at application level. Case 1 ------ Michael advocates calling use 1) "build". For the build case, it is wrong to assume that unwrap(wrap(x)) == x, as, in general, an application level object may not have a 1-to-1 correspondence with an interpreter level object. My opinion is that "unbuild" should not exist. Once an object is built, there is no guarantee that it will ever again correspond directly to an interpreter level object. If we need an interpreter level object out of an application level one, we should do it in a very restricted way, for a specified purpose. If we want an interpreter level object, it is so that we can do manipulations on it, but in general, unwrap and manipulations are not associative: space.unwrap(space.str(w_x)) != str(space.unwrap(w_x)) space.is_true() is an example of such a limited use function. In my mind, is_true() exists for a single purpose - to determine if a wrapped object is true so that the interpreter can determine if a JUMP_IF_TRUE type branch should be taken. Any other use would be considered a "hack". I can perhaps see the need for a .to_string(x) function, with the semantics that "the results of this function are going to be presented directly to the user - I don't care what sort of bizarre and twisted data structure 'x' actually represents, just make a reasonable string so that the human at the keyboard has some kind of feedback for debugging purposes." Use of the output for any other purpose would be highly discouraged. - I would hesitate to add any more such functions until a compelling need for one is demonstrated. Case 2 ------ This is what we are looking for when we say .wrap(frame). Here the role of unwrap depends on how wrap behaves. [If unwrap_2 exists, it should *always* have the semantics that unwrap(wrap(x)) == x] - Possible alternative names for this functionality include shadow() or proxy(). As I interpret it, Armin indicates wrap_2() should create an application level object that shadows an interpreter level object. That is: y = space.wrap(x) print x # <'xyz'> space.fubar(y) #.fubar alters y print x # <'yzw'> and also: y = space.wrap(x) print y # <'xyz'> x.fubar() print y # <'npq'> In implementation, y is just a proxy which passes along the modifications or attribute acesses to the underlying interpreter object, and (unwrap(wrap(x)) is x) is True. An alternative is to have wrap_2() create a new object which retains enough information to recreate an interpreter level object when unwrap() is called. In this case there would be no differences in output for the print statements above, and (unwrap(wrap(x)) is not x) is True. We still have a problem with unwrap if we allow the application level to modify objects produced by wrap_2. Say we have a function object. What happens when someone says: fun.func_name = name in application level code? What if name is generated from the application level and contains an object that represents "92% chance of the string 'MyFun', 7% chance of a class with the .__str__ method hooked up to the fortunes generator, and 1% chance of rain."? The only solution I see is to limit the rvalue to objects that were also created with wrap_2 and thus have their interpreter level values still attached. So in effect, our black box objects become a black hole - values go in, but can never come back out to interpreter level. -Rocco P.S. On further consideration, there is a third solution. We *can* allow an "unbuild" function, with the directive that it is nervous, and raises an exception every time it is the least bit confused at what to do. This allows for free flow of information in the regular cases when we aren't doing anything tricky with the object spaces. My concern would be that we would become dependant on a well behaved unbuild, and require it in a critical piece of code, making development of the clever object spaces difficult to impossible. I'd disapprove of it's use in any code that would be exercised in interpreting the majority of Python scripts. Discourage its use and save it for implementing the dusty introspection/self referential corners of Python only - and be sure to document the expected behavior of the return values well, so any conflicts can be anticipated. __________________________________________________________________ McAfee VirusScan Online from the Netscape Network. Comprehensive protection for your entire computer. Get your free trial today! http://channels.netscape.com/ns/computing/mcafee/index.jsp?promo=393397 Get AOL Instant Messenger 5.1 free of charge. Download Now! http://aim.aol.com/aimnew/Aim/register.adp?promo=380455

Hello Rocco, On Sat, Sep 13, 2003 at 02:24:51PM -0400, Rocco Moretti wrote:
space.is_true() is an example of such a limited use function. In my mind, is_true() exists for a single purpose - to determine if a wrapped object is true so that the interpreter can determine if a JUMP_IF_TRUE type branch should be taken. Any other use would be considered a "hack".
Right. However there are a few other cases in which the interpreter may be interested in "probing" information about a wrapped object. Here are two I can think of: * getting an integer. We need this at a few points, e.g. to know the exact length of a tuple (which is needed to interpret something like "f(*args)"). * getting a (short) string. Again there is an example in arguments decoding, to interpret "f(**kw)" we need to manipulate the keywords. It may be possible to remove all these uses of unwrap (e.g. the length of a tuple can be obtained by iterating over it and counting), but I'd say that it would only make matters more obscure. Instead, just as we have "is_true()" we could do with a few other methods to get the integer value of an object, or its string value.
Case 2 ------ (...) In implementation, y is just a proxy which passes along the modifications or attribute acesses to the underlying interpreter object, and (unwrap(wrap(x)) is x) is True.
Yes, that's the intended purpose. Application-level code that tries to manipulate such a "proxy" wrapped object, as in
fun.func_name = name
will make the object space call back to the interpreter to perform the operation. So the interpreter itself is free to implement the operation as it wishes using unwrap(fun) to get back to its own original object. This is similar to CPython's attribute and method tables, in which C code simulates what is seen at application-level as attribute reading/writing. A bientot, Armin.
participants (2)
-
Armin Rigo
-
roccomoretti@netscape.net