DEV Community

Kirk Lewis
Kirk Lewis

Posted on • Edited on

String Interpolation of Constants in Perl 5

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";
Enter fullscreen mode Exit fullscreen mode

The above outputs:

scalar: 3.14 - list: 3 2 1
Enter fullscreen mode Exit fullscreen mode

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 }";
Enter fullscreen mode Exit fullscreen mode

outputs:

scalar: 3.14 - list: 3 2 1
Enter fullscreen mode Exit fullscreen mode

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 }";
Enter fullscreen mode Exit fullscreen mode

The above results in the following output:

Global symbol "$DEV_OPS" requires an explicit package name...
Enter fullscreen mode Exit fullscreen mode

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 }";
Enter fullscreen mode Exit fullscreen mode

Outputs:

Team dev_ops is online
Team dev_ops - dev_ops is online
Enter fullscreen mode Exit fullscreen mode

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] }...";
Enter fullscreen mode Exit fullscreen mode

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';
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

The above outputs:

blue is invalid
yellow is invalid
orange is invalid
red is valid
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

The above outputs:

blue is valid
yellow is invalid
orange is invalid
red is valid
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (2)

Collapse
 
ribugent profile image
Gerard Ribugent Navarro

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

Collapse
 
choroba profile image
E. Choroba

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';}";