[IPython-dev] ipython1 and synchronous printing of stdout

Fernando Perez fperez.net at gmail.com
Wed Jul 23 23:22:53 EDT 2008

Hi all,

I think we all agree on the fact that we want the combination of loose
coupling, ease of code reuse across actual frontend implementations,
and a reasonable implementation in terms of performance.  The latter
is actually important: while it's true that by using python we've gone
for flexibility over speed, we still need to be careful.  It's not
that hard to write python code that runs slow enough to be a problem
in practice (Traits 1.0 was implemented in pure python, for example,
and it had serious performance issues).

On Tue, Jul 22, 2008 at 1:25 PM, Brian Granger <ellisonbg.net at gmail.com> wrote:

Now, on to what to do next:

> >From this thread, I see a few options:
> 1.  Traits.  While I really like the Traits model and I think it is
> highly appropriate for GUI programming, I think it would lead to too
> tightly coupled code.  Also, we can't use Traits in the core of
> ipython because it has compiled code.
> 2.  Plain callbacks.  At least a couple of us seem to think that an
> interface that has lots of callbacks becomes very cumbersome.
> 3.  The Observer/Delegate pNSDistributedNotificationCenteratterns as are typical is Cocoa.  I know
> that Gael is not fund of this, but I do think this pattern is much
> better than plain callbacks, as it give a nice formal structure to
> everything.  Also, I agree with Barry that this pattern is pretty much
> what you get when you try to do plain callbacks properly.

I think there's a fourth, that Gael mentioned in passing and which
we've been discussing here face to face for a while: using objects
whose basic behavior defines the core API, but which can be given at
construction time instead of being hardcoded in our various __init__
methods.  This allows subclasses (or even non-subclassing application
writers who use the code as a library to build their own tools) to
cleanly provide only the level of behavior modification they need.

I've just gone through the exercise of building the nose plugin for
ipython testing, and I precisely ran into the problem that in many
places, I was forced to copy nose code simply to override a specific
internal object in one place because it hadn't been parametrized.  But
if the nose plugins had more of their components be parametric, it
would have been much simpler to write my code, since all I was doing
was replacing these hard-coded objects with subclasses of the same
that customized one small specific behavior.

This seems to provide a simple solution to our design question: all we
need to do is to  clarify which objects are our core publicly
modifiable components in the API, and then users can tweak only the
parts they need.  Said objects can themselves provide
observer/delegation behavior if they so desire, but they can do it in
the most appropriate way for a given problem.  For example, someone
writing a Traits app (who's already committed to using Traits for
their own reasons) can simply stick in there traited versions of the
same things, and with essentially zero extra code they get the Traits
event model everyhwere.

In a Cocoa environment, these objects could be lightly wrapped
versions of the originals that register (via a modified __getattr__
for example) the necessary observation/update calls into the
NSDistributedNotificationCenter that Cocoa provides, if that's the
best way to do it in such an environment.

And someone who just needs a callback here and there can simply stick
their callback-enhanced object where they want.  I could even see this
being very handy for occasional debugging, by quickly activating
tracing versions of certain objects as needed.

One thing that I like about this approach is that it doesn't
necessarily close the door on a *future* implementation of an
ipython-wide notification center, if we end up finding in practice
that it's really needed as the code grows.  But right now, it seems to
me that this simpler approach solves all of our problems, with the
advantage of introducing exactly *zero* (not small, but truly zero)
overhead for the normal use that has no customizations.

Does this sound reasonable to others, or did I totally miss this
particular boat?  I really want us all to be happy with the solution
we find to this so that we move forward reasonably convinced of it
being viable.



More information about the IPython-dev mailing list