Inversion of inversion of control
Flumotion
Flumotion 0.1.7 "La Chacha" is out the door. All non-masochists interested in live streaming something should give it a whirl. Free software, free formats, easy to use. Don't make baby Jesus cry by using proprietary formats.
Masochists, on the other hand, can continue using icecast.
Inversion²
f = get_file_name() save_to_file(f)
In the good old days, applications were programmed in an imperative, sequential order, where line numbers increased as a process neared completion. So first you get a file name, then you save, and the program remains in control the whole time.
w = file_chooser() connect(w, 'got-file', got_file) event_loop() got_file(f) { save_file(f) }
Then came the rise of application frameworks and inversion of control. Instead of step-by-step processes, we had to make objects that respond to events, and then yield control to the event loop. This creates theoretical problems with state -- instead of state building up on a stack, cancellable at any time by a return statement, it has to persist in these objects and pending events, especially in the lack of real closures. A step towards messiness, but it does allow us to do many things at the same time.
This problem is particularly acute in Twisted, where doing anything interesting will return a Deferred, which is a promise to call back later with the answer. Code becomes a mess of fragmented callbacks, with each able to perform only a fraction of an action before having to defer again. Menos mal that python has closures, albeit crippled ones with a stupid lambda syntax.
Incidentally, this is the same difficulty facing most web applications -- after every page you store state somewhere, then recall it back on another page, without the benefit of a stack. The state management is tough to get right, like programming with gotos but without functions.
So, witness the rise of inversion of inversion of control. Continuation-based web programming frameworks all operate under the same idea of dropping out while the result of a computation is unavailable, then continuing once a process has a result. In the meantime, the server does something else, like handling other people's requests.
f = wait_for (get_file_name()) save_file(f)
In the above pseudo-code, get_file_name returns a deferred result, and wait_for drops out into the event loop until the result is available. I'd do that in python's generators, but wait_for would have to be implemented as a function, and yield only returns to its caller. Python supports semantic abstraction (procedures), but not syntactic abstraction (macros).
@defer_generator def save_stuff(): d = get_file_name() yield d save_file(d.value())
So the deferred results end up being more a part of the procedures, which is OK. defer_generator is a decorator, which means save_stuff = defer_generator(save_stuff). It's implemented in flumotion.twisted.defer. If an error occurrs, d.value() will raise the exception, allowing you to have try/except blocks in deferred programming, even if the operation causing the exception was on another machine. Neat.
@deferredGenerator def save_stuff(): d = waitForDeferred(get_file_name()) yield d save_file(d.getResult())
Twisted people had of course thought of this before, but somehow managed to bungle the idea by wrapping the deferred in seventeen characters (15 for waitForDeferred, two for parentheses -- see the end of twisted.internet.defer). That and the StudlyCaps twisted style, which continues to bother me for irrational reasons.
Meta
Broke down and added a python category on the log. Somehow I find that categorization is a bit dumb though, like the software should do it for me. Other things that bother me: hierarchies of categories, and the random category. Can't quite put my finger on why.
The folks I dig
I'm going home at the end of the month! Just for a week or two, and just to get a Spanish stamp on my passport, but hey, it's an excuse for partying. Rock.
Comments are closed.