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.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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.