loading...

String Interpolation of Constants in Perl 5

kirklewis profile image Kirk Lewis Updated on ・3 min read

This post demonstrates how to use Perl 5 constants with String Interpolation and Regular Expressions. I will briefly explain how String Interpolation works in Perl 5, especially with constants. Finally I explain how to use constants with Regular Expressions, and a use case for this.

String Interpolation

In Perl 5, any scalar or list variables embedded within double-quotes will be substituted with their values at run-time. This type of string is known as an Interpolated String, and it gets resolved in a process known as String Interpolation.

Example:

my $PI   = 3.14;
my @nums = (3, 2, 1);

say "scalar: $PI - list: @nums";

The above outputs:

scalar: 3.14 - list: 3 2 1

Alternatively, Interpolated Strings in Perl 5 can contain an identifier wrapped in either ${} or @{}, and depending on their type, they get resolved accordingly - in this case scalar and list respectively

Example:

say "scalar: ${ PI } - list: @{ nums }";

outputs:

scalar: 3.14 - list: 3 2 1

In the above string, Perl looks-up and finds each identifier i.e. PI and nums within the current namespace, and they are resolved.

Since the expressions ${} and @{} highlight the intent of Interpolation more clearly, I will use them both going forward.

However, a Constant created with the Perl 5 constant prama is Sigilless, as such inserting one into a double-quoted string, will not be resolved. See below:

use constant DEV_OPS => 'dev_ops';
my $status = 'online';

say "Team ${ DEV_OPS } is ${ status }";

The above results in the following output:

Global symbol "$DEV_OPS" requires an explicit package name...

The above occurred because unlike $status, the constant DEV_OPS does not have a sigil, so Perl cannot look it up and resolve it - with regards to quotes ""

Resolving the Constant

To make the Interpolated String aware of any constants to be processed, a backslash \ is used to reference it as follows:

say "Team ${ \DEV_OPS } is ${ status }";
# or if we use more than one constant
say "Team ${ \DEV_OPS } - ${ \DEV_OPS } is ${ status }";

Outputs:

Team dev_ops is online
Team dev_ops - dev_ops is online

List Context

Constant values are evaluated in List context so [] can be used to reference them also. Then use the appropriate interpolation expression as follows:

say "Team @{ [DEV_OPS] }...";

However, I find it simpler to use backslash \.


Using Constants in Regular Expressions

Lets say you have three constants, and each represents a different colour as follows:

use constant BLUE  => 'blue';
use constant GREEN => 'green';
use constant RED   => 'red';

Now, if you have a list of colours @colors which you want to validate against the three colours listed above, you may write something like this:

my  @colors = qw(blue yellow orange red);
my  $colors_regexp = qr/^(blues|green|red)$/; # typo intended...

say $_ =~ $colors_regexp
    ? "$_ is valid"
    : "$_ is invalid" foreach @colors;

The above outputs:

blue is invalid
yellow is invalid
orange is invalid
red is valid

Now blue in @colors is actually valid, but the typo blues in the Regular Expression, causes the match to fail. Whilst this typo is intentional, it could also happen by mistake, and be missed altogether.

Solution

Since each colour is defined as a Constant, it is safer to compose the Regular Expression using each one. This is done the same way I explained earlier, by using a backslash \ to reference each constant.

# lets make the regular expression a constant also
use constant COLORS_REGEXP => qr/^(
    ${\BLUE}  |
    ${\GREEN} |
    ${\RED}
)$/x;

To make the Regular Expression easier to read, I've used the x option. This option allows the Regular Expression to be written on new lines, and white spaces are ignored also.

Finally lets replace the Regular Expression $colors_regexp with the COLORS_REGEXP constant.

my  @colors = qw(blue yellow orange red);

say $_ =~ COLORS_REGEXP
    ? "$_ is valid"
    : "$_ is invalid" foreach @colors;

The above outputs:

blue is valid
yellow is invalid
orange is invalid
red is valid

Conclusion

String Interpolation using Constants in Perl 5 works the same as for scalars and lists, with the exception of using a backslash \ to reference the them. In Perl 6 however, you can just write say "${ constant_name }" and that's it! Perl also has the sprintf function, which allows formatting of variables embedded within strings.

Thank you for reading, and the code used in this post is available on Github.

Posted on by:

kirklewis profile

Kirk Lewis

@kirklewis

Separator of Concerns. I sometimes write about code.

Discussion

markdown guide
 

I didn't know this way to interpolate variables using this notation, also I thought it was impossible to interpolate constants, for this reason at the work we switched from const pragma to Readonly as suggested by the ProhibitConstantPragma perl critic policy

 

The important feature of constants is that they are inlined during the compile time, unlike Readonly. Interestingly,

"${ \CONSTANT }"

still inlines the value, but not the reference and dereference:

$ perl -Mconstant=ABC,42 -MO=Deparse -e 'print ABC, "${\ABC}"'
print '42', "${\'42';}";