Using python coroutines to implement easy of use state machines

Michael 'Mickey' Lauer mickey at vanille-media.de
Mon May 26 22:14:42 CEST 2008


Hi,

On Monday 26 May 2008 05:24:28 Guillaume Chereau wrote:
> I am having a look at the python-ophoned code, and I see that it relies
> a lot on call back functions to implement some sort of state machines.
> (I am not really sure of the real mathematical term I should use)
>
> Something like this :
>
> def process():
> 	print "start process"
> 	# start an asynchronous function
> 	call_asynchronous(an_other_process, call_back = process_next)
>
> def process_next(value)
> 	print "an_other_process returned", value
>
>
> Well, there is a python trick that is getting popular now that can ease
> a lot the implementation of such functions. The idea is to use the yield
> keyword to write coroutines (functions that can be exited and restarted
> at any internal point).
>
> The previous example could be written like this :
>
> def process():
> 	print "start process"
> 	value = ( yield call_asynchronous(an_other_process) )
> 	print "an_other_process returned", value
>

Yeah, I'm familiar with that. To be honest, I already tried doing something 
like that (but it didn't work in 30 minutes and then I gave up ;) since I was 
kind of fed up with all these callbacks. There's two interesting usecases 
here, one with the client and one with the server. In fact, I think it's even 
more important to have that client-side than server-side.

But lets first talk about server. Basically what I'd love to have is instead 
of:

#=========================================================================#
class DeviceSetAntennaPower( DeviceMediator ):
#=========================================================================#
    def trigger( self ):
        self._commchannel.enqueue( "+CFUN?", self.intermediateResponse, 
self.errorFromChannel )

    def intermediateResponse( self, request, response ):
        assert response[-1] == "OK"
        state = self._rightHandSide( response[0] ) == "1"
        if state == self.power:
            # nothing to do
            self._ok()
        else:
            self._commchannel.enqueue( "+CFUN=%d" % self.power, 
self.responseFromChannel, self.errorFromChannel )

    @logged
    def responseFromChannel( self, request, response ):
        if response[-1] == "OK":
            self._ok()
        else:
            DeviceMediator.responseFromChannel( self, request, response )

rather something like this:

#=========================================================================#
class DeviceSetAntennaPower( DeviceMediator ):
#=========================================================================#
    def trigger( self ):
        ( response, error ) = yield( "+CFUN?" )
        if error is not None:
            self.errorFromChannel( error )
        assert response[-1] == "OK"
        state = self._rightHandSide( response[0] ) == "1"
        if state == self.power:
            # nothing to do
            self._ok()
        else:
            ( response, error ) = yield( "+CFUN=%d" % self.power ) 
            if response[-1] == "OK":
                self._ok()
            else:
                DeviceMediator.responseFromChannel( self, request, response )

This would be really nice, more understandable, and more maintainable.

> So my question is : Shouldn't we use this as well ? It is the current
> trend in python programs, and it makes the code much much simpler.

I'm not particular liking the gtasklets (now: kiwi tasklets) implementation, 
but I think you should spend some days trying to see whether you can make the 
aforementioned happen.

> The 
> only problem is that many people are not familiar with coroutine, since
> it doesn't exist in C, and they are not used to write software that rely
> on this.

That should be no problem. People will love that. Like i said, especially on 
the client we see that problem as well. Almost all org.freesmartphone.GSM 
calls should be called asynchronously, since they could block for seconds (or 
minutes, hey, it's a MODEM -- 1990s technology). So, if you could also come 
up for something that makes the dbus calls on the client using result = yield 
(call), I'd be even more happy.

:M:
-- 
Dr. Michael 'Mickey' Lauer | IT-Freelancer | http://www.vanille-media.de



More information about the smartphones-standards mailing list