Abuse of state machines

ziggy on 2003-10-10T01:18:01

Avi Bryant is big on using continuations for implementing web applications. (He's working on a framework to do this with Squeak.)

Avi postulated the other day that a well designed app using continuations is much easier than imperative programming. Today, an enterprising PHP programmmer tried to disprove Avi's postulate by using a simple state machine:

$amount = $_REQUEST['amount'];
$rate = $_REQUEST['rate'];

if( $amount != "" && $rate !=""){
    if(! $amount > 0){
        $t->assign("message", "Amount must be greater than zero");
        $t->display("interestForm.html");
    }else if(! $rate > 0){
        $t->assign("message", "Rate must be greater than zero");
        $t->display("interestForm.html");
    }else{
        $result = $amount * rate;
        $t->assign("result", $result);
        $t->display("interestResult.html");
    }
}else{
    $t->display("interestForm.html")
}
To which Avi responded:
With all due respect: this is spaghetti code, and in any context but web development you wouldn't stand for it either.
Yep. How many overly complex if/elsif/else cascades are in production code today? And what's a better (er, less complex) way to write this kind of simple code?


AxKit, Cocoon

Matts on 2003-10-10T08:02:02

AxKit has a nice forms library called PerForm that works a bit like ASP.NET forms - where you can assign callbacks for each widget. The flow between pages is controlled on a page by page basis (which admittedly isn't as clean as a continuations style system).

Cocoon has a nice sub-language called the "flow", which is continuations based. It's an implementation of Avi's original ideas using Javascript as the underlying language, which is probably the best possible language to choose (given that Perl doesn't do continuations, of course).

I can see where he's coming from though

pdcawley on 2003-10-19T22:24:41

As the constraints associated with a form increase, that set of if/else statements is going to get out of hand, and you're going to have to write custom form handlers for each form on the site. Far better to be able to write, say:

sub Form::handle_request {
        my($self, $request) = @_;
        $self->validate_request;
        return $self->generate_response;
}
sub Form::validate_request {
        my($self, $request) = @_;
        $constraint->validate_request($request);
}
sub Form::generate_response {
          throw Exception::SubclassResponsibility;
}

Now, because your constraints are responding to a simple interface, you can develop various different types of more or less useful contraint types. The beauty of Avi's continuation based system is that resolving those constraints can simply look like function calls from the calling context but which could look like an n step wizard to the user (and changing what it looks like doesn't require any changes in *any* calling contexts that use the same wizard).

Note that I'm expecting 'handle_request' to be wrapped in a
$response = eval {...} || $@; $response->display
type handler. (Admittedly, relying on everything to throw an exception that has a display method is possibly a little courageous...)

I don't claim that this is simpler for the subcase presented, but I do claim that, as a site grows, moving towards a design where behaviour can be pushed out to metadata is a good thing.