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 AUTOLOAD
ed 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?
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.
Like this:
Like Loading...