Writing Declarative Perl

At The Perl Conference in Washington DC, I'll be giving a talk on Modeling a Universe in Perl. For previous versions of this talk, people have asked for more information about how we model complex actions in a (mostly) declarative manner. For example, here's the code for purchasing a clone:

It's the Steps() function which is our declarative code. As you might imagine, there are tons of actions which might require that you be in a particular area, or have credits removed from your wallet, so the Area and Wallet lines can be dropped into any Steps() function anywhere throughout our code. But people want to know how this works. In reality, it's pretty simple.

Here's a slightly more complicated example (example taken from some docs and 5 internet points to whoever first spots the bug):

First, remember that each step is an "SVO" (subject-verb-object) sentence. That's key to understanding what follows. The sub name, such as Location(), is short-hand for the class and the SVO arguments help to build the instance.

All of the above is therefore a wrapper around OO code. Steps() is actually a constructor which (sort of) takes a list of economic action objects. Area is a constructor for a Veure::Economy::Asset::Area instance and the second argument, the verb (is_in) is a method on that object. The first argument, the subject (the $character) is the main recipient of the behavior and any following arguments are argument to the is_in method.

Thus, Area( $character => is_in => 'inn' ) translates (roughly) to:

Veure::Economy::Asset::Area->new( subject => $character )
                           ->is_in('inn')

And that returns a boolean object (along with appropriate messages to return to the character indicating success or failure). The Steps() constructor creates a an object that iterates over each step so long as they return a true boolean object. Some steps (FAILURE) will only be called if previous steps have failed and others are might ALWAYS be called.

The code above also handles logging, sending messages to the player, and database transactions. The developer no longer needs to think about this. That's sort of a lie because it tremendously oversimplifies what we have, but it represents the core of the implementation.

Plus, we can cut-n-paste a series of Steps() for non-technical people and they can still read what we've done. It's awesome.

And that's why people hire us. We make code that's easy to follow and use and we only hire the best.

(I think for my next talk, I should explain why our remote teams often outperform on-site teams)

3 Comments

Interesting post.

As far as the bug goes, it seems like there's a FAILURE consequence, but not a SUCCESS consequence. So I'm guessing that line should instead be something like

SUCCESS ( Wallet( $character => add => $bet_amount ) ), ..

Nice and clear syntax! Very inspiring.

Adding cash to the Wallet is the last step. Without knowing the exact mechanisms I guess there will be a problem if one of the first steps fails as FAILURE will then remove cash that has not been added?

Personally I find declarative programming very obfuscated for two reasons:

  1. Call to attempt() is outside Steps(). That is the very core of declarative programming - to separate process definition from its execution. But this leads to:

  2. Unclear SUCCESS/FAILURE triggering. "If Wallet( ... hasminimumcredits .. ) step is not met does that mean FAILURE should be triggered?". In this case obviously not - if there was no bet no funds should be taken from wallet. But this is way too blurry.

Leave a comment

About Ovid

user-pic Freelance Perl/Testing/Agile consultant and trainer. See http://www.allaroundtheworld.fr/ for our services. If you have a problem with Perl, we will solve it for you. And don't forget to buy my book! http://www.amazon.com/Beginning-Perl-Curtis-Poe/dp/1118013840/