Paul D. Fernhout wrote:
> Ian Bicking wrote:
> 
>>Paul D. Fernhout wrote:
>>This is a little of what I intend with HTConsole; the objects are 
>>(vaguely) live, and potentially shared.  Though I've only implemented 
>>useful liveness for functions so far.  It's at conflict with the idea of 
>>source code, and live objects really require an image, and I've never 
>>liked images.  So I'm not sure if it's a useful path.
> 
> 
> Ian-
> 
> Thank you for your detailed reply and I promise more thought on it, but on 
> this one issue, to respond immediately, consider my earlier comments on 
> images and the muse as to a potential "Pythonic" resolution. Basically, it 
> is to think of the Python *image* as being defined by a Python *program* 
> that builds an object world and is stored in a textual *.py file, and just 
> looks and acts like regular Python source code -- ideally with comments 
> preserved too. So, no pickled objects, not binary image files, just Python 
> source code as readable text that rebuilds hierarchies and meshworks of 
> objects.

That's very hard to implement...

For instance, imagine the user does this:

   x = [1, 2]

Then they get a handle on that [1, 2] list (we'll call it OB1) and do 
"OB1[0] = 5".  How do we represent that as source?  Because they are 
acting on actual objects, not bindings, and OB1 doesn't have any name, 
nor will it exist at the same address in a second run of the program.

In order to turn this into source, you'd have to keep track of how you 
can repeatably get to OB1 (I guess you'd see that it was named "x" 
through source introspection?), and then translate operations on that 
object into source that does operations on the path to that object.

I think doing this generally becomes infeasible, though you can get 
close through successively more bizarre source code generation, until 
you end up with something that looks like a Python-source version of 
pickle, and even that won't work very well.


This is all not to say that modifying Python source in a manner 
different than ASCII is infeasible.  Only that "source" and "runtime" 
have to be kept separate to keep this process sane.  Images -- which 
mingle the two -- have never felt sane to me; clever, but not 
manageable.  Unfortunately we do not have very good abstractions in 
Python related to source, so they have to be invented from scratch.  The 
AST might help, but higher-level abstractions are also called for.  For 
instance, you might define a color interactively in some fashion, and 
the color gets serialized to:

   import color
   color.Color(r, b, c)

That color object might be immutable (probably should be), but the 
*source* isn't immutable, and the source means something.  How can we 
tell what it means?

I can imagine a bit of interaction between the source and the runtime to 
do this.  For instance, we might see that "color" is bound to a specific 
module, and "color.Color" to a specific object.  We'll disallow certain 
tricks, like binding "color" dynamically, monkeypatching something into 
"color.Color", etc.  Ultimately figuring out exactly what color.Color is 
isn't *easy*, but at least it is feasible.

Using existing introspection we can figure out some parts, some of the 
sorts of things that IDEs with auto-completion figure out.  They can 
figure out what the arguments to Color() are and the docstring.

But, you can also imagine adding an editor or other things to that 
object; a richer form of __repr__, or a richer editable form than the 
ASCII source.  Maybe there would be a flag on Color that says it can be 
called without side effect (meaning we can speculatively call it when 
inspecting source); and then the resulting object might have something 
that says it can be displayed in a certain way (with its real color), 
and has certain slots you can edit and then turn into a new Color 
invocation.

This is where the 'make' syntax starts to come into play again, or more 
generally where declarative source comes into play.  Take a typical 
non-declarative module, like optparse:

   parser = OptionParser()
   parser.add_option('-v', '--verbose', action='store_true', 
dest='verbose', help='Be verbose')

There's nothing there that looks like a literal; the first call to 
OptionParser isn't very interesting, all the structure is in later 
parts.  This on the other hand:

   make OptionParser parser:
       make Option verbose:
           """Be verbose"""
           aliases = ['-v']
           action = 'store_true'
           dest='verbose'

that is really a much more fully-formed piece of source that can be 
understood as a complete piece; you could add methods to OptionParser 
and Option to make this usefully editable.  (Or use generic functions to 
avoid having to modify those objects to give them rich source 
representations)

Sometimes declarative structures are in conflict with runtime 
dynamicism, but I don't think they have to be.  The declarative form 
doesn't make the .add_option() method obsolete; it just offers a static 
form for the most common case where you statically construct the 
options.  There also might be a hint of static typing here -- an 
OptionParser source editor might suggest an option to add another 
Option, and so it will be bound to the Option class specifically; but 
it's just important to leave in the same generality in the source editor 
as the original source has.  That is, OptionParser should defer to 
Option for the 'verbose' key that's already set.

This is all harder than what HTConsole is doing currently, mostly 
because Python source introspection is much poorer than Python object 
introspection.


> It is also risky in another way, because loading a Python program could do 
> anything to you system (unless we have Python VMs with Java like security 
> limits on writing to files or sockets, where the VM enforces the 
> restrictions internally from security flags). 

Loading a Python program can already do anything, if you put the 
commands at the top-level (not in a function).  So Python source really 
is focused on constructing objects -- even functions and classes are 
*built* by the source, not declared by it, and so circular imports and 
circular class references can be challenging as a result.


-- 
Ian Bicking  /  [EMAIL PROTECTED]  /  http://blog.ianbicking.org
_______________________________________________
Edu-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/edu-sig

Reply via email to