NAME
Perl::Critic::Policy::Misc::ProhibitMethodsInStringConcat - Prohibit method calls in string concatenation
VERSION
version 0.01
DESCRIPTION
This policy flags method calls used as operands to the . (string concatenation) operator.
Why?
When Perl concatenates strings and an operand is undef, it emits a warning. The quality of that warning depends on the operand's form:
my $result = "Name: " . $obj->name() . " Age: " . $obj->age();
produces:
Use of uninitialized value in concatenation (.) or string at ... line N
No indication of which method returned undef. On a long concatenation line the developer must manually bisect to find the offending call.
By contrast, assigning the result to a variable first:
my $name = $obj->name(); # warns: Use of uninitialized value $name ...
my $age = $obj->age();
my $result = "Name: " . $name . " Age: " . $age;
Perl names the variable:
Use of uninitialized value $name in concatenation (.) or string at ... line N
The variable name pinpoints the source of undef immediately.
This difference matters because method calls are opaque -- the call expression has no name that Perl can surface in the diagnostic. A scalar variable, on the other hand, carries its identifier through to the warning.
Using printf / sprintf avoids the problem altogether by separating the template from the value list, making each argument a distinct expression on its own line or position.
Remediation
# Instead of -- method call hidden inside concat:
my $result = "Name: " . $obj->name() . " Age: " . $obj->age();
# Option 1 -- unload to a variable first:
my $name = $obj->name();
my $age = $obj->age();
my $result = "Name: " . $name . " Age: " . $age;
# Option 2 -- use sprintf (separates template from data):
my $result = sprintf 'Name: %s Age: %s', $obj->name(), $obj->age();
EXAMPLES
my $x = "Hello " . $obj->name(); # not ok
my $x = $obj->name() . "Hello"; # not ok
my $x = 'hello' . ( $foo->bar / 2 ) . 'there'; # not ok (method in parens)
my $name = $obj->name(); # ok -- unload to variable first
my $x = "Hello " . $name;
my $x = sprintf 'Hello %s', $obj->name(); # ok -- use sprintf
The policy traverses into parentheses, so method calls nested inside parenthesized sub-expressions within a concatenation are also flagged.
.= (concat-assign)
The .= operator is not flagged when used with a single method call:
$x .= $obj->method(); # ok -- single method, clear intent
However, when the right side of .= itself contains . concatenation with method calls, those inner . operators are flagged:
$x .= $obj->method() . $obj->other(); # not ok (inner .)
$x .= "Name: " . $obj->method(); # not ok (inner .)
CONFIGURATION
This policy does not accept any configuration parameters.
SEE ALSO
Perl::Critic, "Use of uninitialized value %s" in perldiag
AUTHOR
Dean Hamstead <dean@fragfest.com.au>
COPYRIGHT AND LICENSE
This software is Copyright (c) 2026 by Dean Hamstead.
This is free software, licensed under:
The MIT (X11) License