pericmd 011: Give me functions and I will move the world

In the previous posts I’ve talked about the DRY principle and wanting to avoid repetitions. After thinking a bit more about this again, I am reminded that it boils down to functions.

I want to only write the code once for local backend as well as for remote backend.

I also want to only write the code once for each environment: CLI or HTTP API or Perl API module. Because when you think about it, what a CLI program does is essentially parse command-line options and then pass it to some function. And in HTTP API or web forms, we essentially parse HTTP request and eventually pass it to some function. And of course, when we use a Perl module, we deal with functions.

So I only want to write each function once and not be bothered with the plumbing.

I only want to care that I get a list of arguments for my function, do my stuffs that I’m supposed to do in the body of the function, and then return the result. All the rest is mostly just “fluff”. This is the purest form of programming, because functions are essentially mini programs: they accept input, do processing, and return result/output. They are simple.

What about objects? Sure, they’re neat too. But they are less versatile than functions. Functions can be used in a purely stateless way, which maps better to the ubiquitous HTTP request-response stateless protocol. Objects, on the other hand, are stateful by definition. You could use objects in a stateless way too: for each request you instantiate them, call some method, and destroy them at the end of the request. But if you did this then why bother with objects at all.

But to automate plumbing when working with functions in the different environments, we will need to add more metadata to them. Perl (most programming languages, actually) only let us specify a list of argument names (sometimes types too) for a function, perhaps some attributes, and also the type of return value. If we want to use a function as a CLI program, we will need to specify how to map command-line options to function arguments, for example. We could just let arguments map 1-to-1 to command-line options, for example ‘foo’ to –foo, ‘bar’ to –bar, but often it’s nice to be able to specify some shortcut options. Adding summary/description text for the function and each argument would be nice as well, as it will allow us to generate a help message automatically.

And that’s the whole idea of the specification called Rinci, which defines a set of properties and attributes for your functions (and variables and packages and a few other code entities).

From the previous post’s source code, here’s the Rinci metadata for the function:

$SPEC{create_sparse_file} = {
    v => 1.1,
    summary => 'Create sparse file',
    description => <<'_',

Sparse file is a file with a predefined size (sometimes large) but does not yet
allocate all its (blank) data on disk. Sparse file is a feature of filesystem.

I usually create sparse file when I want to create a large disk image but do not
want to preallocate its data yet. Creating a sparse file should be virtually
instantaneous.

_
    args => {
        name => {
            schema => ['str*'],
            req => 1,
            pos => 0,
        },
        size => {
            summary => 'Size (e.g. 10K, 22.5M)',
            schema => ['str*'],
            cmdline_aliases => { s => {} },
            req => 1,
            pos => 1,
        },
        interactive => {
            summary => 'Whether or not the program should be interactive',
            schema => 'bool',
            default => 1,
            description => <<'_',

If set to false then will not prompt interactively and usually will proceed
(unless for dangerous stuffs, in which case will bail immediately.

_
        },
        override => {
            summary => 'Whether to override existing file',
            schema => 'bool',
            default => 0,
            description => <<'_',

If se to true then will override existing file without warning. The default is
to prompt, or bail (if not interactive).

_
        },
    },
    examples => [
        {
            argv => [qw/file.bin 30G/],
            summary => 'Create a sparse file called file.bin with size of 30GB',
            test => 0,
        },
    ],
};

You can see that basically the metadata contains the summary and description of a function, as well as list of arguments and a few of other stuffs. The next several posts will discuss this metadata in more detail.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s