Perl: Spaces in a function or method name

I accidentally stumbled over an interesting ability/quirk in Perl: a subroutine / function / method name may contain spaces. Since I couldn’t find any info about it in the perlsub man page or on Google I decided to write it down.

It should be obvious that you can’t create such a subroutine by defining it the traditional way, but in case it isn’t: you can’t. Perl will consider the first word to be your subroutine identifier, and the following word(s) to be invalid keywords.

use strict;

sub name With Spaces
{
    print "works!\n"; # liar, doesn't work
}
Illegal declaration of subroutine main::name line 4.

NOTE: the following examples were tested in Perl versions 5.8.8 (circa 2006), 5.14.2 (circa 2011), and 5.28.2 (circa 2019).

To create a method name with a space, you have to manipulate the symbol table directly. (Indeed, I figured it out by accident thanks to an AUTOLOADed method that did that.)

sub AUTOLOAD
{
    my $self = shift;

    ( my $method = $AUTOLOAD ) =~ s{.*::}{};

    if ( exists $self->{_attr}->{ $method } ) {
        my $accessor = sub { return shift->{_attr}->{ $method } };

        {
            no strict 'refs';
            *$AUTOLOAD = $accessor;
        }

        unshift @_ => $self;
        goto &$AUTOLOAD;
    }

    return;
}

Stated more simply:

my $name = "name With Space";
*$name = sub { "works!" }; # insert directly to symbol table

Utilities like Test::Deep “just work” if there’s a space:

cmp_methods( $obj,
             [ 'name With Space' => 'value' ], # not a peep!
             'Basic methods'
            );
ok 1 - Basic Methods

The obvious question, though, is how to access it directly? Answer: references!

You can access a method using a variable, which is a pretty common thing to do on it’s own. (In my experience, anyway, YMMV).

my $name = 'name With Space';
my $value = $obj->$name; # works!

You can also create a reference to a string and immediately deference it.

my $value = $obj->${ \'name With Space' }; # works!

The second example works with regular function calls as well. Here’s a stand-alone example:

use strict;

{
    no strict "refs";
    my $name = "name With Space";
    *$name = sub { "works!" };
}

print ${ \"name With Space" }, "\n";' # prints "works!"

I can’t recommend creating subroutines with spaces in the name as good style, but it’s helpful to know that it can happen and how to work with it when it does.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.