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