Re: [Edu-sig] FYI: PataPata postmortem link

Ian Bicking wrote:
There's some similar issues being considered for OLPC. Specifically the laptop has a "view source" key, which (unsurprisingly) lets you view the source of what you are doing. What that means is application (aka "Activity") specific, but a general Python solution is called for.
Of course it's a little hard to say what that actually should be. Just a text editor? Not too exciting. Really there should be a view of the process. And some way to manipulate the in-process objects and source.
When I hear something like this, I think of pipelines or trees of self-contained components rather than source-level objects. Wasn't there a talk at EuroPython 2006 about data processing that covered this approach? [...]
Of course, at some point you need complete power, which means editing the source in ways that can only be meaningful when you restart the process from scratch. I'm not sure how or where to make that break. OTOH, emphasizing clean/fast/easy restarts might be more general and easier to implement than in-process persistent editing.
In many ways, it's more interesting to consider making modified copies of existing processes. It avoids difficult issues with in-process interaction and encourages something like a prototype-based approach. It seems to me that this might work well with simple components, but maybe I'm just trying to avoid facing those difficult issues. :-/
I'm also not sure what to build on, or what to use. It's interesting that you felt out-of-process interaction was successful. This fits with my own intuition that in-process stuff can be dangerous and fragile. But I'm not that familiar with the details of how the interprocess communication should happen; perhaps IDLE is a good place to start looking. Perhaps IDLE is a good place to start the development?
My experiments have led me to believe that interaction between processes using their standard input, output and error streams is a fairly robust foundation on which to implement out-of-process editing facilities for use with simple editing environments. David

David Boddie wrote:
There's some similar issues being considered for OLPC. Specifically the laptop has a "view source" key, which (unsurprisingly) lets you view the source of what you are doing. What that means is application (aka "Activity") specific, but a general Python solution is called for.
Of course it's a little hard to say what that actually should be. Just a text editor? Not too exciting. Really there should be a view of the process. And some way to manipulate the in-process objects and source.
When I hear something like this, I think of pipelines or trees of self-contained components rather than source-level objects. Wasn't there a talk at EuroPython 2006 about data processing that covered this approach?
There's certainly tree-like structures in memory (and pipeline, and cubbies, and all sorts of other data structures). And it's entirely reasonable to create a browser for these objects, where you can inspect and traverse those in-memory objects. Where that currently falls down is that while you can change those objects, that change is not generally persistent. When the process is restarted, it will restart just like it was before. Given a more constrained concept of object that included a persistence system, you could make that object manipulation meaningful. But then you need a persistence system -- which notably Squeak has, and that's an idea most fully explored in Python in Zope 2 (with through-the-web development). Including a persistence system introduces a lot of complications, because key parts of the application have been moved into your persistence system and out of your source code. I'd like to avoid this (I wasn't a very happy Zope 2 through the web developer). In particular cases it might be more reasonable. For instance, consider glade (http://glade.gnome.org/) -- it's an XML description of a GUI. For an application that uses Glade and given an editor specific to that, you could edit the "objects" and then the XML is automatically written out. You'd be doing simultaneous editing of the in-process objects and the "source code", in this case the XML description of the layout. Glade isn't magic, of course -- you could add automatic serialization to any kind of object, or recreate something like Glade in Python. For a small number of basic Python objects this is already possible; mostly functions. Modules and classes are not nearly so simple. But really if we can cover a set of compelling things that children would want to edit, an incomplete in-process editing system could be valuable.
[...]
Of course, at some point you need complete power, which means editing the source in ways that can only be meaningful when you restart the process from scratch. I'm not sure how or where to make that break. OTOH, emphasizing clean/fast/easy restarts might be more general and easier to implement than in-process persistent editing.
In many ways, it's more interesting to consider making modified copies of existing processes. It avoids difficult issues with in-process interaction and encourages something like a prototype-based approach. It seems to me that this might work well with simple components, but maybe I'm just trying to avoid facing those difficult issues. :-/
Forking would clone a process. But this doesn't get around the reload problem. I could go into the details, but there's lots of tricky aspects to reloading a module in Python. The reload() function is totally stupid -- it's just equivalent to: def reload(mod): exec open(mod.__file__).read() in mod.__dict__ As a result there's lots of references to the old objects. For every class there is now two instances of the class. Any imports like "from mod import Foo" will still be pointing at the old Foo. There might be references to functions, bound methods, etc, and old instances with a __class__ pointing to the old definition. People have implemented fancier reloaders that do better. For instance, recursively replacing the __dict__ of classes, instead of just creating a new class. There are always cases in which these fail. That said, if we could identify those cases and give warnings we'd be getting a lot further. Current reloaders are optimistic and ignore detectable problems. Once the warnings are in, and given alternate methods (e.g., alternatives to mutable class-level variables), we would be encouraging people to write reloadable code. -- Ian Bicking | ianb@colorstudy.com | http://blog.ianbicking.org

Ian Bicking wrote:
There's certainly tree-like structures in memory (and pipeline, and cubbies, and all sorts of other data structures). And it's entirely reasonable to create a browser for these objects, where you can inspect and traverse those in-memory objects.
Where that currently falls down is that while you can change those objects, that change is not generally persistent. When the process is restarted, it will restart just like it was before.
You previously brought up the issue of "knowing the state of an object vs. knowing how it got that way" in the context of development tools for kids and the OLPC project. Which makes me think about something related to my Pointrel data repository approach, some examples of which (including in Python) are here: http://sourceforge.net/projects/pointrel/ and also in a subdirectory called Pointrel of the PataPata project code (where I implement a crude Smalltalk environment but on top of Python). http://sourceforge.net/projects/patapata Essentially, the Pointrel system stores triples (sometimes quads or octs) which denote the change in state of the system over time. So, for example: Relation# A B C 1: X value 10 2: Y value 20 3: X value 20 4: Y Value 10 5: Y Value 20 This could be interpreted as showing two variables X and Y changing their values. (In practice this would be more complex, I'm just simplifying this here). You coudl also imagine: Relation# A B C 0001: X value 10 0002..0101: [internal changes (e.g. stack) for bytecode processing] 0102: Y value 20 0103..1002: [internal changes (e.g. stack) for bytecode processing] 1003: X value 20 1004..2003: [internal changes related to code processing] 2004: Y Value 10 2005..3004: [internal changes related to code processing] 3005: Y Value 20 The key thing is that if you also use the system to store the state related to the processor in one stream of changes (which the version I put in PataPata does, although not maybe general enough here as I tried to split it up into two memory steams of changes in that particular version), then, when you want to know what the state was of the system when any variable was changed, your tool could look at the most recent change to a field, and then working backward from there, see what the current state of the program was. This is sort of like storing a stack trace or the state of the machine whenever any pixel is set, but now it is looking at it in terms of when any variable is set (or *any* other changer is made). So, with the right tools, it would be at least easy for a novice programmer to see what was changing a piece of code. Now there still remains the problem you raise -- where to intervene if you want a persistent change. And also, there remain the complex logical problem of then pursuing a set of changes back in time and mapping them onto programmer "intent". Anyway, I thought I'd just mention this aspect of some versions of the Pointrel system, because with people always choosing to use (more robust) relational database systems like Postgres or MySQL, and with the ascendance of RDF for storing triadal information, and as other opportunities have passed by (e.g. easily adding OO to C) during the more than twenty years I've played around with these concepts, the Pointrel system has become a bit of a solution still looking for a good problem. :-) But clearly here is a problem it could solve (and I have always liked the Pointrel system for its promise of being able to do that, although, to be fair, OCaml manages something similar when its debugger steps backwards in time by using checkpoints and recalculating state from them -- although it can't deal well with IO issues which might be different during the recalculation from a checkpoint). Anyway, what occurs to me is I have never thought of emphasizing this aspect of being able to step backwards in the debugger as well as easily find the point in time when a variable was changed (as well as the state of the entire system at that time) in the context of a programming environment for *beginners*, so that is an idea I have to think about. And, it also lets you find out when any pixel was changed, if bitmaps are stored within triads. Of course, this is all very inefficient in some senses to store all this information and to search it, but in a system for small applications it might not be noticeable, or if it was noticeably slow, it still might be worth the wait for beginners in some situations (although in general beginners need faster systems then experts because they make so many more mistakes and a fast cycle time lets them learn faster and better). Again though, it does not solve the problem of how to make changes (persistent or not) once you have that information by understanding what state the system was in (and the related intent of the code) when of interest something happened in a way other than what you wanted. But maybe it could be linked with some other approaches that did (perhaps Smalltalk-like in terms of an image of live objects). --Paul Fernhout
participants (3)
-
David Boddie
-
Ian Bicking
-
Paul D. Fernhout