Monday, April 1, 2013

Overriding Global Methods In Perl

In Ruby, for some work I've done recently, a coworker added some utility functions to help working with Lists, Maps and Arrays. In Ruby an array appends elements using the << operator, so by adding such an operator to his helper class he was able to have the helper code be a drop-in replacement for Ruby Arrays.

Now working in Perl, I needed to do something similar for arrays. But in Perl arrays aren't instances of any class, and my replacement is going to be just that. In Perl if you want to append to an array you use the global method:

    push(@array, $scalar);

My goal was to supplant this method with my own and, when @array is an instance of my new class (qpid::proton::ArrayHelper) do one thing. If, however, it's just a plain old Perl array then I want to call the standard function from Perl.

Sound difficult? Nope, it's easy.


To replace the global function with your own, you can simply do this:

    BEGIN {
        sub qpid_proton_push(\@ \$) {
            my (@array, $value) = @_;

            # if this is my array type, then do one thing
            if(isProtonType) {
                # do one thing
            } else {
                # call the original function
                CORE::push(@array, $value);

        # assign push to my new method
        *CORE::GLOBAL::push =&qpid_proton_push;

The solution defines a new method and then points the global function pointer to it. The reason I chose this solution rather than pointing to an anonymous method was that I needed to declare a method prototype for qpid_proton_push. Since the first argument is an array type then a prototype was necessary to let Perl know how to handle the arguments.