satchboost has asked for the wisdom of the Perl Monks concerning the following question:

Yes, having read all the wonderful stuff up above, I know I shouldn't be using $` and $'. However, I don't have much of a choice because where I work still hasn't upgraded to 5.60. (I do have a request in to ITS, though...) So, I've got the following code:
my ($foo, $bar) = (123, 456); my $base_string = "#200"; $base_string =~ /^#/ ? $foo = $' : $bar = $base_string; print "$foo $bar\n";
This prints out "#200 456" when it should be printing "200 456". Now, I noticed that if I split the trinary up into a if-else, it worked just as expected. Why would that be?

Replies are listed 'Best First'.
Re: Why won't $' work in a trinary operation?
by japhy (Canon) on Feb 05, 2001 at 20:53 UTC
    The problem is that your ?: line is parsed by Perl as:
    ($base_string =~ /^#/ ? ($foo = $') : $bar) = $base_string;
    Add parens to your expression to get the operations to occur in the right manner:
    $base_string =~ /^#/ ? ($foo = $') : ($bar = $base_string);
Re: Why won't $' work in a trinary operation?
by chipmunk (Parson) on Feb 05, 2001 at 21:03 UTC
    This gotcha is explained in the standard documentation for the conditional operator in perlop:
    Because this operator produces an assignable result, using assignments without parentheses will get you in trouble. For example, this: $a % 2 ? $a += 10 : $a += 2 Really means this: (($a % 2) ? ($a += 10) : $a) += 2 Rather than this: ($a % 2) ? ($a += 10) : ($a += 2)
Re: Why won't $' work in a trinary operation?
by Fastolfe (Vicar) on Feb 06, 2001 at 00:39 UTC
    To avoid this confusion, never use the trinary operator in a void context (when you have no intention of using the value returned). It's usually clearer to write it out, and avoids messy precedence issues like this. Remember that ?: is built so that it can be used in expressions as a replacement for a single value in a complex operation.

    If all you're using it for is to control execution (make one assignment versus another), use a normal if/else construct:

    if ($base_string =~ /^#/) { $foo = $'; } else { $bar = $base_string; }
    Arguably using /^#(.*)/ and $1 instead of $' is going to be a bit more efficient. Generally it's best to shy away from $` and $', as these add costly operations to an otherwise straightforward regex match.
(tye)Re: Why won't $' work in a trinary operation?
by tye (Sage) on Feb 06, 2001 at 03:31 UTC

    I have a different rule for avoiding this problem: Whenever you do an assignment in an expression, put parens around the assignment. There are lots of things beside ?: that will bite you when you put an assignment inside of an expression, for example, ($new=$old) =~ s/x/y/g;

            - tye (but my friends call me "Tye")
Re (tilly) 1: Why won't $' work in a trinary operation?
by tilly (Archbishop) on Feb 06, 2001 at 03:58 UTC
    What version of Perl are you running that you have to use $'? Explicit backreferences have worked for ages. Just use a pattern like /^#(\d+)/ (modify to taste) and assign $1.

    Using $' or $` anywhere in your program slows down *every* RE possibly dramatically. So Don't Do That.