On Mon, Sep 12, 2011 at 7:38 PM, Owen Taylor <owta...@gmail.com> wrote:
> build replot.Axes() as p:
>
p = replot.Axes()
p.plot(x, sin(x), 'bo')
p.plot(x, cos(x))
p
works because of some inner logging magic, but that doesn't work well
for a lot of things. For example, from
http://www.reinteract.org/trac/wiki/SidebarDesign, we mght want to do:
surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 200, 200)
cr = cairo.Context(surface)
cr.set_source_rgba(1,1,1) # white
cr.paint()
cr.set_source_rgba(1,1,1) # black
cr.move_to(0, 0)
cr.line_to(100, 100)
cr.stroke()
surface
which not only doesn't work, it isn't natural to write. With
refigure2, Robert came up the idea of doing magic behind the scenes so
that a 'with' statement could magically output as the last thing it
did:
with Figure() as f:
plot(x, sin(x), 'bo')
plot(x, cos(x))
The figure is then output as a "result" of the with statement. Though
I'm not fond of the implicit figure object and the global functions
that act on it, I think that's pretty neat. But the issue is that now
we've made 'with' do something that with doesn't do - have a "return
value" that gets output. It seems to me that if we want to extend
Python it's better to go ahead and /extend/ Python in a clear way -
and indeed, we can do magic at the rewrite step so:
build Figure() as f:
f.plot(x, sin(x), 'bo')
f.plot(x, cos(x))
works without requiring any magic from the implementation of Figure().
This also extends naturally to the idea of a sidebar; since we're now
defining the output before drawing on it, it make sense to support:
build Figure(float=Right) as f:
f.plot(x, sin(x), 'bo')
f.plot(x, cos(x))
so the figure pops up in a sidebar to the right of the worksheet.
Possible variants
=================
* Allow not providing a variable name, and have some default:
build Figure():
_.plot(x, sin(x), 'bo')
_.plot(x, cos(x))
* Make it possible to use a naked build: as a synonym for 'if True'
for grouping side-effectful statements:
build:
f = open("/etc/passwd")
passwords = f.read()
f.close()
* Allow not supplying an initializer but just a name for the case
where the variable can't be allocated up front:
build as passwords
f = open("/etc/passwd")
passwords = f.read()
f.close()
Proof of concept
================
To show that the "magic at the rewrite step" is not an empty claim,
the attached patch makes something like the last variant work, so you
can do:
build passwords
f = open("/etc/passwd")
passwords = f.read()
f.close()
<outputs passwords>
This isn't really saying this is the best variant - I think using 'as'
for naming is likely better, it's just what I happened to have in my
head when I started implementing.
http://git.fishsoup.net/cgit/reinteract/tree/examples/build.rws
I went ahead and implemented most of the possibilities discussed in my
last mail - except for the implicit '_' variable, which seemed more
like Perl than Python.
- Owen
This is very cool. Unfortunately, it doesn't work for me with Python
2.6. (I'm guessing you're using 2.7?) The AST for the with statement
is different from the pattern in rewrite.py. I've figured out a fix
works in 2.6 and I think doesn't screw up 2.7, though I haven't tested
that. Here's the bug and the patch:
https://bugzilla.gnome.org/show_bug.cgi?id=659113 It's sort of a
brute-force solution, but I figured this section of the code is
complicated enough without adding more code paths.
>
> I went ahead and implemented most of the possibilities discussed in my
> last mail - except for the implicit '_' variable, which seemed more
> like Perl than Python.
The implicit _ strikes me as too clever, promising to cause confusion.
If you need the build variable, it's not that hard to name it.
Thanks,
Robert
Sorry about that ... glad you figured a way to get it working. We used
to do something like that for Python 2.4 support. (See commit
917ef386a for where it was removed), so I'm not opposed to that kind
of thing, though I'd wonder if we could figure out a way to share the
code and only use different patterns.
I actually started working on a rewrite last night to make rewrite.py
use the ast module rather than the parser module - working with the
abstract syntax tree rather than the raw parse tree. Boy is it simpler
that way! Still a bit from actually trying running it, so I'm not sure
if that's a short term direction or not. If it doesn't work out or is
going to take a while to land, we can definitely go with something
like your patch. If it does work out, we'll probably need some testing
on different Python versions there too, though hopefully it will be
more robust against inter-version differences.
- Owen