Sign In/My Account | View Cart  
advertisement


Listen Print Discuss

Making Sense of Subroutines
by Rob Kinyon | Pages: 1, 2, 3, 4

What Should I Call It?

Naming things well is important for all parts of your code. With subroutines, it's even more important. A subroutine is a chunk of work described to the reader only by its name. If the name is too short, no one knows what it means. If the name is too long, then it's too hard to understand and potentially difficult to type. If the name is too specific, you will confuse the reader when you call it for more general circumstances.

Subroutine names should flow when read out loud: doThis() for actions and is_that() for Boolean checks. Ideally, a subroutine name should be verbNoun() (or verb_noun()). To test this, take a section of your code and read it out loud to your closest non-geek friend. When you're done, ask them what that piece of code should do. If they have no idea, your subroutines (and variables) may have poor names. (I've provided examples in two forms, "camelCase" and "under_score." Some people prefer one way and some prefer the other. As long as you're consistent, it doesn't matter which you choose.)

What Else Can I Do?

(This section assumes a strong grasp of Perl fundamentals, especially hashes and references.)

Perl is one of a class of languages that allows you to treat subroutines as first-class objects. This means you can use subroutines in nearly every place you can use a variable. This concept comes from functional programming (FP), and is a very powerful technique.

The basic building block of FP in Perl is the reference to a subroutine, or subref. For a named subroutine, you can say my $subref = \&foobar;. You can then say $subref->(1, 2) and it will be as if you said foobar(1, 2). A subref is a regular scalar, so you can pass it around as you can any other reference (say, to an array or hash) and you can put them into arrays and hashes. You can also construct them anonymously by saying my $subref = sub { ... }; (where the ... is the body of the subroutine).

This provides several very neat options.

Closures

Closures are the main building blocks for using subroutines in functional programming. A closure is a subroutine that remembers its lexical scratchpad. In English, this means that if you take a reference to a subroutine that uses a my variable defined outside of it, it will remember the value of that variable when it was defined and be able to access it, even if you use the subroutine outside of the scope of that variable.

There are two main variations of closures you see in normal code. The first is a named closure.

{
    my $counter = 0;
    sub inc_counter { return $counter++ }
}

When you call inc_counter(), you're obviously out of scope for the $counter variable. Yet, it will increment the counter and return the value as if it were in scope.

This is a very good way to handle global state, if you're uncomfortable with object-oriented programming. Just extend the idea to multiple variables and have a getter and setter for each one.

The second is an anonymous closure.

Recursion

Many recursive functions are simple enough that they do not need to keep any state. Those that do are more complicated, especially if you want to be able to call the function more than once at a time. Enter anonymous subroutines.

sub recursionSetup {
    my ($x, $y) = @_;

    my @stack;

    my $_recurse = sub {
        my ($foo, $bar) = @_;

        # Do stuff here with $x, $y, and @stack;
    };
    my $val = $_recurse->( $x, $y );

    return $val;
}

Inner Subroutines

Subroutine definitions are global in Perl. This means that Perl doesn't have inner subroutines.

sub foo {
    sub bar {
    }

    # This bar() should only be accessible from within foo(),
    # but it is accessible from everywhere
    bar():
}

Enter anonymous subroutines again.

sub foo {
    my $bar = sub {
    };

    # This $bar is only accessible from within foo()
    $bar->();
}

Pages: 1, 2, 3, 4

Next Pagearrow