25 years

February 25, 2008 at 12:23 AM | categories: python, oldblog | View Comments

Well, this year will mark the 25th year that I've been writing code, so at some point later in the year I'll probably have some sort of party/drinks relating to that, since it means something (not sure what :-) ) to me. I have to decide a date where that makes sense, maybe some of the following will make sense. This post is a bit self indulgent as a result.

I can't give a particular date, but I suspect the date is probably sometime around easter 1983 - based on some very vague memories. I'd been interested by computers and programming for a couple of years at that point, mainly due to seeing some schematics in Doctor Who weekly saying how to build your own K9. I've found the cover of that magazine here for those who wonder what got me interested.

Anyway, the idea of making a robot dog - especially when you're given schematics, is like a red rag to a 7 year old. Have cardboard boxes, will get started. Anyway over the next couple of years, amongst all the other things little boys do, I read more about robots and so on in kids books and it became more clear that in order to build a robot, you needed to know about computers. As a result the "maker" culture that's sprung up in California amuses me - in a good way (it's a good thing after all) - it was this desire to "make" something that drew me into software in the first place.

It's worth stopping here and considering this: the schematics for K9 looked like something a child could, with effort, actually make. That moved it from the realms of complete fantasy and unreachable into the realms of the possible (which is of course what good science fiction really is). Not only that, it made robots and computers seem like something a child could do, rather than "just" something to be watched. Having seen the schematics again some years later, it is rather beyond the scope of a 7 year old, but that wasn't really the point.

Fast forward a couple of years, and my brother (David) had been interested in programming since they'd done something to the Commodore PET at school which meant they'd been encouraged to fix it. The side effect is that eventually David (then aged 12 I think) promised to explain the BASICs to me.

I still remember the first program I tried to write. I'd been told at that point that "computers have to be told everything, and require very precise instructions and can tell you things". So I wrote down my first program, and the next time we were near Dixons in Lion Yard in Cambridge, (then next to the library) I typed it into one of them (I think a Vic 20).

Unsurprisingly, it didn't actually work because of a rather major missing detail in the above - the fact that computers use special languages for their instructions.

For your amusement, here's that first program (more or less):
"You are a computer
 I am a human
 What are you?"

Since I was 9 at the time at the absolute oldest, I'm going to give myself some credit here - it was a good try, and but with more experience I can see just how demanding a set of conversations that is to a machine with less than 16K of RAM. (I was more or less expecting the machine to pass a subset of the Turing test I now realise, which is an entertaining assumption!)

Fast forward a little while (autumn '83) and my brother had by then taught me the basics of BASIC, what a string was, etc and I was good to do, sans the detail of not actually owning a computer. At that point in time (1983), my Dad got hold of a ZX81 - hardly cutting edge then (the ZX Spectrum existed, in not only 16K but also whizzy 48K version - the ZX81 had a whopping 1K of memory - 0.4K actually usable, and a 16K RAM pack), but it was the first micro I had any access to, beyond playing with the microcomputers in Dixons and Boots. (Looking back, I think those shops were remarkably tolerant in comparison to today!) Heck, they were being almost given away as prizes at the fairground. However, it was a real computer, and it did work.

Co-incidentally, we also moved back to Cambridge - near Waterbeach, and the primary school I was going to had a book club. So I saved up all my pocket money and at that book club bought my first ever book on computer programming, and to this day I still rate it as the single best book ever that introduced programming. It could be updated I think, but would be difficult to improve.

It was targetted at children, and as a result had fun pictures and diagrams - which were all hand drawn & illustrated - but were largely of little robots running around inside a computer. (See, things go full circle sometimes :-). The robots were tasked (literally) with running around moving bits of data from here to there. To sending stuff to the display, putting dots into a big grid to draw pictures. They stood in front of racks of boxes (much like an old fashioned hotel lobby with pigeon holes for keys/messages) where data was put & labelled and so on.

Quite simply it was fantastic :) Not only that, but it was only 48 pages long. Yes. 48 pages.

For those that remember, yes, this was one of the Usborne computer books, and I'm amazed at how dumbed down they've become over the years. (I picked up their "Starting Computers" a few years back to see how it'd "improved"... :-/ ) They were perfectly targetted - they were marketed as part of their "scholastic" series in schools as suitable for 9-12 year olds, and they were perfect. They showed you how to make games. Some how to do graphics. Another taught you electronics projects, and yet another even showed you how to make a robot.

Whilst I still have my book on Computer Graphics and on "how to build your own robot" from those days, I'd mislaid that book: Introduction to Computer Programming - by Brian Smith. However, many years later I'd borrowed from the library an omnibus book "The Beginner's Computer Handbook" - which featured 3 Usborne books in one: "Understanding the Micro", "Introduction to Computer Programming" & "Computer Space Games". That, along with other usborne books of the time were highly responsible for boot strapping my early interest.

By 1984 I'd written a simple "Logo" interpreter. Come 1985 or so, my parents splashed out on a Commodore Plus/4 and for various reasons (mainly fun), I ended up writing a pre-emptive task switching monitor in 6502 assembler for it. (Yep, aged 12 or 13 I wrote an incredibly basic pre-emptive multitasking operating system for an 8 bit micro those who understand what all those words mean.)

Then along came the Amiga, and I kept on building, eventually leading to writing a paint program for my GCSEs - but this was different - you painted notes on a scale - so you literally painted music. That was probably, ironically, one of the few times I've been forced to struggle with a microsoft product - since that was writting in Amiga Basic - which was written by Microsoft. It was also probably one of the last large programs I ever wrote in basic. I've completely forgotten what I did for my 2nd year a level computer science course now. It was some sort of database system.

Part of the reason for that being my last BASIC program is probably due to finding the astounding book "The Cartoon Guide to Computers" by Larry Gonick. Aside from anything else what's perhaps most astounding about it is that it teaches you enough electronics, enough boolean logic, enough about how logic gates work, how a computer is subdivided into its constituent elements, not just in a high level way, but all the way down to how microcode inside a CPU works to implement CPU opcodes that you write for assembler. Stunning book. It was the logical next step after the Usborne books. From then on it was Pascal & C which lead to Amiga E & Standard ML - which taught me object oriented programming and functional programming respectively.

Given my experience of using a pre-emptive multitasking OS, and having written the basics behind it myself before the age of 16, it should come as little surprise that I wasn't particularly impressed with Windows 3.0 when it came out some years later, and the fact it locked up when it shouldn't. Moving from the Amiga to Unix however was pretty natural.

Anyhow, enough digression, I continued to progress, with formal education, but always with a fair amount of play with new ideas. It's easy to think that because I work with computers that somehow I went through the route that some people have of cross training after an unrelated degree, or that I simply did a computer science degree because I couldn't think of anything better to do. However, the reality is, whenever I start something new, learn something new to do with a computer, I'm still learning with that same enthusiasm I had as a 9 year old.

Show me the results of applying text mining to the output of the BBC website, and I jump with glee, not  just wanting it, but knowing how realistic it is to want. Show me multi-touch, and I instantly see that all I'm waiting for is a display that I can actually work with to do something fun with it. Tell me that there's a new speech synthesiser package for Linux that actually works and I integrate it with Kamaelia:
Pipeline(
    Textbox(position=(20, 340),
                     text_height=36,
                     screen_width=900,
                     screen_height=400,
                     background_color=(130,0,70),
                     text_color=(255,255,255)),
    PureTransformer(lambda x: str(x)+"\n" ),
    UnixProcess("while read word; do echo $word | ./espeak -w foo.wav --stdin ; aplay foo.wav ; done")
).run()
Yes, that's a toy. But it's fun. Partly for me, partly for others. But I now wonder why my system doesn't talk as much as it could. After all the above can be integrated with anything, so sooner or later my computer will be talking more. Or it'll find its way into a system that needs to talk.

However, we come back now to full circle. The extremely observant among you will have noticed this above:
"The robots were tasked (literally) with running around moving bits of data from here to there. To sending stuff to the display, putting dots into a big grid to draw pictures. They stood in front of racks of boxes (much like an old fashioned hotel lobby with pigeon holes for keys/messages) where data was put & labelled and so on."
In Kamaelia, my primary metaphor has always been "imagine someone sitting at a desk, with a bunch of intrays(inboxes) and out-trays. They do work based on the data they recieve and send it out the out-trays. Then another person - a postman - comes along and moves the data from the out-trays to the in-trays.". Now clearly this is a metaphor - but there's a few things I've learnt about computers over the years:
  • Metaphors matter.
  • Good metaphors are hard to come up with, perhaps the hardest thing in computer science.
  • That if you can think of a metaphor, you can use it to write code.Therefore, why not pick one that you enjoy?
  • Any good metaphor can be represented by using pictures of humanoid robots.
And that last point brings us to the silly little secret in Kamaelia. When I'm thinking "someone sitting at a desk", I'm picturing a Kids book on Kamaelia with little robots sitting at a desk. When I'm saying "someone comes along to do deliveries", I'm thinking more little robots with roller skates on doing the deliveries between components. When I added in the Co-ordinating Assistant Tracker - the assistant - it was very much added in because there's a very practical metaphor there - that of a team assistant. (You have a team of little robots all working together, and they tell the assistant what they're doing if they're willing to get requests from other robots)

So there you have it, not only am I really wanting to make Kamaelia accessible to the average developer, I'm actually thinking of the average 9-10 year old who wants to be a developer - or perhaps even the 6 1/2 -7 year old who decides "I want to build K9", and at the end it's really due to me remembering how I got here - an interest in building K9, books explaining to kids how robots work, books explaining to kids how to program, the cartoon guide to computing (and underlying electronics, physics and signal theory...), Simula BEGIN, and many more similar books, and hardware/software systems that made these things doable, all in short friendly descriptions, but ones which weren't skin deep.

The books you get today are just awful. 100s (or 1000s) of page tomes on introducing a concept that used to be possible to explain to a 9 year old in a 48 page book with pictures of robots. It must be possible to get back to that stage. Even the "head first" books are awful - they're a nice idea, but just too large to be actually any use IMO. Anyhow, if no-one writes that book, I guess I'll just have to update the usborne books of years ago with something new. (Which, I do actually plan to do - I've scoured amazon and similar for places selling the originals, and getting somewhere there)

The new book will have to deal with video, multimedia, TV, games, 3D, as well as things like web, and all that whizzy stuff, with a nice and easy way of bolting these things together, but in a way that prepares anyone reading it for a world of writing concurrent software. It's always been an underlying agenda in Kamaelia, but this year I think that'll have to happen.

Along with finally making a real K9 :-) (more on that anon)

Read and Post Comments

Javascript turtle

January 25, 2008 at 09:05 AM | categories: python, oldblog | View Comments

A turtle/worm written using javascript: http://languagegame.org/tmp/jstile/exp/worm.html
Read and Post Comments

Register Article on cross platform iPlayer "issues"

January 15, 2008 at 12:42 AM | categories: python, oldblog | View Comments

I tend to understate certain things sometimes. From The Register article: MP accuses BBC chief of illegally championing Microsoft - John Pugh - MP for Southport:
As part of a Public Accounts Committee session on BBC procurement last Tuesday, the director-general was grilled by Liberal Democrat John Pugh MP on the decision to release the download version of the iPlayer for Windows and Internet Explorer only.
...
Pugh followed up the meeting with a letter to Thompson on Wednesday. He wrote: "By guaranteeing full functionality to the products of one software vendor [the BBC] is as a public body handing a commercial advantage to that company - effectively illegal state aid!

"What might be a pragmatic choice for a privately funded company becomes deeply problematic for a public corporation."
The full article is well worth a read - especially for those who think that technology decisions in a public corporation don't have a political angle. (This is why generally R&D has historically aimed on producing technologies and facilities and understanding, with the aim of allowing such decisions to be informed, rather than taking them. At least that's what they keep telling me :-)
Read and Post Comments

Parsing XML in Kamaelia using an expat parser

January 13, 2008 at 03:05 PM | categories: python, oldblog | View Comments

Generally we've used sax for parsing XML, but it's useful to show how to parse XML using a parser like expat that works by calling back into your code. The trick, as usual with anything long running, is to put the thing that does the long running call into a thread and have it emit messages when a callback is called. The following is a minimal example:
import time
import Axon
import xml.parsers.expat
from Kamaelia.Chassis.Pipeline import Pipeline
from Kamaelia.Util.Console import ConsoleEchoer

class Parser(Axon.ThreadedComponent.threadedcomponent):
    data = "<h1> Default </h1>"  # Can be overridden by kwargs as normal

    def start_element(self,name,attrs):
        self.send(("START", name,attrs), "outbox")

    def end_element(self,name):
        self.send(("END", name), "outbox")

    def char_data(self,data):
        data = data.strip()
        self.send(("DATA", data), "outbox")

    def main(self):
        p = xml.parsers.expat.ParserCreate()
        p.StartElementHandler = self.start_element
        p.EndElementHandler = self.end_element
        p.CharacterDataHandler = self.char_data
        p.Parse(self.data, 1)
        time.sleep(1)
        self.send(Axon.Ipc.producerFinished(), "signal")

Pipeline(
    Parser(data="<body><h1>Hello</h1> world <p>Woo</p></body>"),
    ConsoleEchoer(),
).run()
This generates the following output:
('START', u'body', {})('START', u'h1', {})('DATA', u'Hello')('END', u'h1')('DATA', u'world')('START', u'p', {})('DATA', u'Woo')('END', u'p')('END', u'body')
The nice thing about this of course is that this then allows you to test the thing that's taking this information in isolation from the XML handling code. Indeed, it allows for a much simpler test harness overall.
Read and Post Comments

Debugging Kamaelia Systems

January 13, 2008 at 02:56 PM | categories: python, oldblog | View Comments

One thing that is particularly useful when debugging Kamaelia systems - especially servers - is the ability to dump out what's running. Fortunately Kamaelia provides a mechanism to introspect the scheduler, so you can do this as follows:
import time
import Axon
from Kamaelia.Chassis.Pipeline import Pipeline
from Kamaelia.Util.Console import ConsoleEchoer

class PeriodicWakeup(Axon.ThreadedComponent.threadedcomponent):
    interval = 300
    def main(self):
        while 1:
            time.sleep(self.interval)
            self.send("tick", "outbox")

class WakeableIntrospector(Axon.Component.component):
    def main(self):
        while 1:
            Q = [ q.name for q in self.scheduler.listAllThreads() ]
            Q.sort()
            self.send("*debug* THREADS"+ str(Q), "outbox")
            self.scheduler.debuggingon = False
            yield 1
            while not self.dataReady("inbox"):
                self.pause()
                yield 1
            while self.dataReady("inbox"):
                self.recv("inbox")

Pipeline(
    PeriodicWakeup(),
    WakeableIntrospector(),
    ConsoleEchoer(),
).activate()

Note: this construct won't shutdown.
This produces output of the following kind:
*debug* THREADS['Kamaelia.Chassis.Pipeline.Pipeline_11', 'Kamaelia.Chassis.Pipeline.Pipeline_7', 'Kamaelia.Internet.TCPClient.TCPClient_9', '__main__.Listener_10', '__main__.PeriodicWakeup_5', '__main__.WakeableIntrospector_6']
This turns out to be, as you might expect, to be particularly useful.
Read and Post Comments

Wish list for component systems in python

January 13, 2008 at 01:32 AM | categories: python, oldblog | View Comments

Interesting wishlist for kamaelia (and others, but I'm interested from a kamaelia perspective) here: http://darkness.codefu.org/wordpress/2007/12/26/295
I'm not sure I buy all the criticisms, and feel they're more a wish-list in terms of improvements specific points mentioned about kamaelia as (IMO) potential wishlist items:
  • "the implementation needs to be updated to support the new features of generators in Python 2.5...." - that I don't buy particularly. The new features of generators are : you can now do try..finally (which was a wart, and is just a matter of using that in new code) Another is that you can send values directly into a generator. If you do that, you effectively make your generator synchronous (or at best isochronous) with the caller. I'm not convinced by a long shot that's a good thing and it feels like a mistake in the language. However by chaining with a pub/sub generator you may be able to gain somethng a bit erlang-ish (to do the matching). I'm not convinced though. The other major thing is that you can send exceptions in to kill a generator. Now that is useful, but is something we'll only do when we decide to kill off completely the kamaelia on python series 60 - which is something I'm not sure I want to do yet. The other point is "how do you model that correctly in other languages" - which is unclear.
  • "....as the current syntax strikes me as rather ugly." - is the other half of the sentence. That can be true at times, though I think the use of WaitComplete and the new STM code makes this somewhat nicer - cf the greylisting server.
  • "In fact, it looks like Kamaelia needs a recent release, period: the last one I saw was from 2006." - ouch! I hadn't realised it had been quite as long as that. That's actually quite embarassing! It was on my todo list, but I'll take that on board.
  • "Kamaelia also fails to offer multi-process operation" - yep. This is something I don't make any bones about - we wanted to make sure that the current API was useful and used it in a variety of scenarios before moving this forward. The recent experiments I've made here suggest this should be relatively simple to achieve. (multiwindow pygame, first multiprocess test)
  • The idea of a networked pipe seems desirable as well given this: "it needs a way to generalize its “wires” to support communication with, e.g., remote components. You could actually combine the marshalling component with the framing component and a TCP client/server components and make this work" - this is something I've played with in /Sketches - but that's nowhere near the level I'd want to use as yet - partly because we hadn't at that point really got a feel for how this could be useful. (That's changing) However, this isn't something I've had a real chance to move forward at all.
  • The code should be able to migrate from microthread to thread to process as desired. This comes back to the idea that ThreadedComponent should be a chassis (ala FirstProcessBasedComponent) rather than a component you instantiate. (that would allow the threaded component to accept any component into running in its thread). This is something I realised early on could be a real problem when it comes to the issue of shared data. However the recent STM code designed to replace the dictionary in the CAT could be a real boost there. Definitely worth reconsidering. This opens up the general idea of proxy components further.
  • Components in multi-language- this seems at odds with the request to use more features of python generators. My guess is actually the core would be a core set of constructs,and then a predefined inter-language comms style. I've been leaning towards JSON more and more lately, and this would certainly hit the multi-language compatibility & ease of working with issues.
Beyond that however there's also an implication of a desire for lower level configuration as well - along the lines of Shards as experimented with by Tara last summer. All of this is doable, but with limited time, its debatable how much kamaelia can satisfy all these things, especially when I'm the only person working on it, with little feedback. As a result I'll focus on the areas I'm getting feedback on :-)

All in all though - useful wish list & food for thought.



Read and Post Comments

Axon.STM 1.0.1 - New Release

December 24, 2007 at 11:59 AM | categories: python, oldblog | View Comments

Just posted this to comp.lang.python - but posting here as well :-) I've received some great feedback since the initial beta release of the minimalistic STM code I discussed and released 2 weeks ago. I've incorporated the feedback, and created a couple of examples based on the canonical dining philosophers example. (One based on normal python threads, one based on Kamaelia)

It turns out that there was a potential race hazard during "using" and "usevar" which I'd missed - many thanks to Richard Taylor for pointing out this issue.

Changelog
1.0.1
  • Improved locking. (fixed race hazards during copying for reading - the last release was noted as probably OK for CPython, but maybe not for Jython or IronPython. This version is more robust)
  • Added Dining Philosophers examples (threading & Axon threading)
Getting it
You can download this release version here:
http://thwackety.com/Axon.STM-1.0.1.tar.gz
Installing it
tar zxf Axon.STM-1.0.1.tar.gz
cd Axon.STM-1.0.1/
sudo python setup.py install
What IS it?, Why is it useful?, Docs? Using it?
See website :-)

DIning Philosophers?
See last blog post!

Pure python version in subversion as well.

Thanks for this release
Many thanks go to Richard Taylor for detailed feedback and discussion regarding locking and for pointing me at MASCOT which made me think of doing the dining philosophers this way

Future
This will be merged onto the mainline of Kamaelia with some auxillary functions , as another feather aimed at making concurrency easy to work with :-) Note: For the moment to use this alongside Kamaelia you install this, then reinstall Axon over the top.

Read and Post Comments

Dining Philosophers In Kamaelia

December 23, 2007 at 11:36 PM | categories: python, oldblog | View Comments

After playing around with the STM code, and spotting the dining philosopher's code in the MASCOT example/manual that I found, I've now implemented the traditional dining philosophers example using Kamaelia. This is largely about acquiring and releasing resources - something we largely do in a really simplistic way right now, and have explicitly excluded threaded code from directly accessing.

Implementing STM makes it possible to extend this to threaded code as well, and the dining philosophers example is a pretty canonical example.
#!/usr/bin/python

# First some imports...

import random
import time
import Axon
from Axon.STM import Store

# And a single support function to make code clearer :-)

def all(aList, value):
    for i in aList:
        if value != i:
            return False
    return True


# We can then define a dining philosopher as follows:

class Philosopher(Axon.ThreadedComponent.threadedcomponent):
    forks = ["fork.1", "fork.2"] # default for testing :-)
    def getforks(self):
        """
        Essentially what this says is:
           * I have a number of forks I'm expected to try and pick up.
           * So I grab a copy of the global state.
           * Check to see they're not owned by anyone:
              X[fork].value == None
           * If they're not, then setting their owner to "me":
               X[fork].value = self.name
           * Then try to commit that change of ownership
        """
        gotforks = False
        while not gotforks:
            try:
                X = self.store.using(*self.forks)
                if all([ X[fork].value for fork in self.forks], None):
                    for fork in self.forks:
                        X[fork].value = self.name
                    X.commit()
                    gotforks = True
                else:
                    time.sleep(random.random())
            except Axon.STM.ConcurrentUpdate:
                time.sleep(random.random())
        print "Got forks!", self.name, self.forks
        return X

    def releaseforks(self,X):
        """
        If that works, then I have the forks, otherwise I sleep and retry.
        I then later release the forks by setting their values to None and
        committing back.
        """
        print "releasing forks", self.name
        for fork in self.forks:
            X[fork].value = None
        X.commit()

    def main(self):
        while 1:
            X = self.getforks()
            time.sleep(0.2)
            self.releaseforks(X)
            time.sleep(0.3+random.random())

# The final bit of the code simply sets the system in motion:
S = Store()
N = 5
for i in range(1,N):
    Philosopher(store=S,forks=["fork.%d" % i ,"fork.%d" % (i+1)]).activate()

Philosopher(store=S,forks=["fork.%d" % N ,"fork.%d" % 1]).run()

The upshot of this is, personally, I find this relatively clear and relatively simple. It is also the sort of thing that you can wrap up neatly into a relatively reusable piece of code (which is of course the sort of thing I like to do :)

One thing I'm tempted to do is to change this to emit when a philosopher picks up/puts down a fork since you could animate this in a fun way I suspect :-)

Read and Post Comments

Software Transactional Memory updated - Code Review Sought!

December 20, 2007 at 12:49 PM | categories: python, oldblog | View Comments

I've updated the STM code in subversion at present here:
https://kamaelia.svn.sourceforge.net/svnroot/kamaelia/branches/private_MPS_Scratch/Bindings/STM/Axon/STM.py
I would really appreciate any code review from anyone who's capable of doing so - even if you've never done a code review before! Things I think need particular attention is the detail around locking. Specifically the following 4 methods are intended to be used by a user of the code:
class Store(object):
    def usevar(self, key):
    def set(self, key, value):
    def using(self, *keys):
    def set_values(self, D):
The above 4 functions entirely manage the locking. The following functions are internal and all assume that the store is locked appropriately before an update attempt:
    def __get(self, key):
    def __make(self, key):
    def __do_update(self, key, value):
    def __can_update(self,key, value):
Anyhow, why is this useful? Well, it turns out this should make resource management a lot simpler. If I'm right, the following code should be sufficient for the Dining Philosopher's problem:
take forks... (pseudo python, ignoring various details)
not_have_forks = True
while not_have_forks:
   try:
      S = <get the store from somewhere>
      forks = S.using("fork.1", "fork.2")
      if forks["1"].value == None and forks["2"].value == None:
          forks["1"].value = id(self)
          forks["2"].value = id(self)
          forks.commit()
          not_have_forks = False
   except ConcurrentUpdate:
       time.sleep(random()) # random backoff - doesn't guarantee success
   except BusyRetry:
       time.sleep(random()) # random backoff - doesn't guarantee success
eat()
# Put forks back - should always succeed. Should. :-)
try:
    forks["1"].value = None
    forks["2"].value = None
    forks.commit()
except ConcurrentUpdate:
    pass
except BusyRetry:
    pass
... which I think is pretty neat :-)

What inspired me to this? Well, there's been a thread on the Python UK list recently about my STM implementation, which resulted in a discussion about a system called "MASCOT" being discussed. Essentially MASCOT looks incredibly similar to Kamaelia - at least superficially. From my perspective, the mere existence of MASCOT and its various subsystems which looks very similar I think validate a lot of the core ideas in Kamaelia. I want to write a post up about that separately though.... More later!

Anyhow, back to this, if anyone is willing to code review the STM code here:
https://kamaelia.svn.sourceforge.net/svnroot/kamaelia/branches/private_MPS_Scratch/Bindings/STM/Axon/STM.py
I'd greatly appreciate it!

Read and Post Comments

Concurrency - The difference between functional call context & object context

December 17, 2007 at 10:25 PM | categories: python, oldblog | View Comments

A common idiom in functional programming at least with the functional languages I've used and systems I've needed to build - is a call context. That is any sufficiently large functional piece of code is at some level modelling interacting with a model. So in pseudo-functional-language you (conceptually) end up doing something like:
fun move_x context distance:
   let
       x,y,z = Parts(context)
   in
       return Context(x+distance,y,z)
   done
This context then gets passed around, and updated. This means you can end up with lots of functions that look like this:
fun move_x contet ...
fun move_y context ...
fun move_z context ...

This looks very similar to something you get in python:
def move_x(self, ...
def move_y(self, ...
def move_z(self, ...

However there's a big difference. In the object oriented python (or almost any other OO language really), the value of "self" is a persistent value (ie exists while someone has a reference to it), and "self" is itself mutable.

This has some implications that you don't have in a functional world for concurrency. For example, you could model and pass on an updated  indication something is locked something like this:
fun ..with_lock context ...:
   let
       x,y,z,_ = Parts(context)
   in
       return Context(x,y,z,"locked")
   done
ie simply update our functional object to say that the state is locked. That sounds remarkably similar to doing something like this:
def ..with_lock(self, ...
     self.locked = True
    ....
However, remember the difference here. In the functional version the Context is (logically at least) creating a completely new value, with the exception of the fact that one attribute of the structure is different. However the OO version is mutating a piece of storage.
This is perhaps the simplest example I can see of how a functional style is easier to work with in a concurrent world with shared data, and perhaps also what aspect of shared data is dangerous.

You see, because the functional style essentially takes a value and copies it before mutating it, it naturally means that the only bits of code that see the copy are the pieces of code called next. eg:
def hello(context, count):
    if count >1:
        return hello("hello"+context, count -1)

In this example the context just bigger and bigger and bigger. It is however never shared - except explicitly. Just because on the surface it looks similar, it's nothing like it. The coding and design principles look similar, but they're not. The fact is it is object oriented, but it's a  functional object and it is only visible within the thread that created it. If someone else has another object that looks the same, that's nice, but it isn't the same.

(All of this goes back to fundamentals of functional languages)

However, if I create an object in an OO language, I can easily create a collection of threads that can mutate that object. As soon as I do, in an object oriented language, without hackery what one thread of control can see about the object, all threads of control can see about the object. That's right - all attributes become instantly shared data.

This means that suppose I acquire a lock, and wish to pass this onto another function I'm calling. In a functional language, I can merely update the value in the (thread-of-control-private) context, whereas in the OO language, I can't update the context. I have to create a new functional context to pass around if I wish to achieve something similar. ie I have to do this:
def meth(self, callcontext, ...)
Where callcontext contains the new indication saying we're locked.

As a result, this leads me to ponder:
The core problem here, as ever, in the OO version isn't just shared state - it's shared mutable state
More than that it's also the fact that the mutable state can't be easily used to control thread local state by default.

Doesn't that open the door to something more halfway? Add support for thread private object values? I guess this is what Unified Functions and Objects - UFO (which I use many years ago) - did - I just never appreciated what it was really doing. (Or if it didn't, what it should've done :-)

I think what this also suggests (to me) is that thread local storage actually needs promoting to a much higher level - to the extent that updates to objects default to updating attributes in thread local storage rather than direct unmanaged update - with the idea being that the managed updates can then be managed in a somewhat better manner.

Hm. I suppose what that is saying is that the mutable shared object state should default to being software transactional memory, whereas the version you normally access is thread local, since then you would (hopefully) get the best of both worlds...

Hm, shared self.__dict__ as an STM , and threads accessing it only doing so through special dict proxies which get commited ? hmm.....

Read and Post Comments

« Previous Page -- Next Page »