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?

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.

New LEAF

Meghan got a new job here in town a while back.  More to the point, it’s two miles away.

I realized after a while that her car wasn’t really getting a chance to get up to operating temperature very often, even in the middle of summer.  She makes several trips throughout the day to various buildings around town, but they’re rarely more than a couple of miles per hop.

This is the worst-case scenario for a gasoline-powered car.  Her mileage suffered considerably: she was barely getting 20 mpg.  I knew that the car would shortly show signs of fast aging — this is part of the “severe driving” section of the manual.

After hemming and hawing a bit, we decided that the best way to protect our asset would be to go electric.  (I can’t say “protect our investment” because, lets face it, cars are not investments.)  Meghan is the best-case scenario for an electric: lots of starts and stops (which lets regenerative braking recapture lots of energy) and no range anxiety since she’s never far from home.

We did our research, tried out a few cars, and finally found a good match.

Introducing Meghan’s new-to-her 2016 Nissan LEAF SL

Meghan's New LEAF
Meghan in her new Nissan LEAF.

Another shot of the front:

Front of LEAF

Highlight of the Week

My personal highlight of this week:

Just finished a 20 mile bike ride with Meghan.  We’re sitting in a McDonalds in Danvers.  At the table next to us, we’re listening to a 99 year old guy (gonna be an even 100 next month!) come over and start chatting up a group of 80-something women.

Classic Marinara Sauce

Ingredients

  • 1 28-ounce can whole San Marzano tomatoes, certified D.O.P. if possible
  • 1/4 cup extra-virgin olive oil
  • 7 garlic cloves, peeled and slivered
  • Pinch of crushed red pepper flakes
  • 1 teaspoon kosher salt
  • 1 large fresh basil sprig, or 1/4 teaspoon dried oregano, more to taste

Steps

  1. Pour the tomatoes into a bowl and crush them with your hands
    1. Afterwards, fill the can about 1/4 to 3/4 way with water; slosh around to capture the tomato juices and bits, and set aside for a moment.
    2. Use more water if you want a lot of sauce, or are finishing meatballs, or want it to simmer for a long time.  Use less water if you don’t have much time
  2. Slice the garlic cloves as fine as you can
  3. Put the pan on medium heat and add the olive oil
  4. When the olive oil starts to shimmer, toss in the garlic and let it sizzle
  5. BEFORE the garlic starts to brown, pour in the tomatoes, followed by the water from the can, and sprinkle on the oregano and pepper flakes.  If you’re using fresh basil, lay it on top.
  6. Turn down the heat and let the sauce simmer for 30 minutes to an hour.  It will get a nice orange-y color to the top.  You can reduce it until there’s no visible water, but no more than that – remove it from the heat if you reach that point!

Notes

  • This recipe is great because it’s tasty and doesn’t take a lot of extra work, but it does take time.  Expect prep plus cooking to be an hour.
  • You really want to use a heavy stainless pan, 12″ or larger.
  • Our local grocery store carries canned whole San Marzano tomatoes, and they are certified D.O.P., but they already have basil added (so we don’t actually put additional basil in).
  • I’ve tried using canned crushed tomatoes but it messes with the texture and flavor.  Crushing them yourself is easy yet so satisfying.
  • Our best experience was making meatballs at the same time, and finishing them off in the sauce.  The sauce picked up some extra flavors that made it sublime.

Source: https://cooking.nytimes.com/recipes/1015987-classic-marinara-sauce

Sausage and Vegetable Roast

This is a kind of suggestion-type recipe, throw in your favorite vegetables and ignore the ones you don’t like (or don’t want to do today).

Ingredients

  • Two medium-sized red potatoes
  • 1 head of broccoli (or cauliflower)
  • 2 bell peppers (use two different colors, for the look)
  • 1/2 pound green beans (a couple of handfuls)
  • 1 bunch of asparagus
  • 3/4 pound of sausage
  • Olive oil
  • 1/4 cup grated Parmesan cheese
  • 1/4 teaspoon red pepper flakes
  • 1/2 teaspoon garlic powder
  • 1 tablespoon dried oregano
  • 1 tablespoon dried parsley
  • 1/4 teaspoon salt
  • 1/4 teaspoon pepper

Steps

  1. Heat up an oven to 400° F
  2. Cut up the potatoes into small (less than 1 inch) pieces. If they’re too big they won’t cook fast enough
  3. Cut up the broccoli, peppers, and asparagus into comfortably-bite-size pieces, and snap the stems off the beans
  4. Slice the sausage into “coins”
  5. Toss veggies, sausage, cheese, and spices into a large bowl with enough olive oil to lightly coat everything (a few tablespoons)
  6. Spread out onto a couple of pans
    1. Everything should be a single layer; doubling up will lead to a mix of burnt and raw bits
  7. Bake for 15 minutes
  8. Flip the veggies and reverse the pans top to bottom
  9. Bake for another 10-15 minutes

Serve with brown rice!

Variations

Swap in a cup of any of the following:

  • butternut squash
  • zucchini
  • sliced carrots
  • a sweet potato
  • turnip
  • radishes
  • sliced jalapeños
  • cherry tomatoes (cut in half)
  • red onions
  • mushrooms