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

If I run the following code:

#!/usr/bin/perl -w use strict; my %test_hash = ("foo_bar" => "baz"); my $test = "foo"; my $key = "${test}_bar"; my $var1 = "aaa/$test_hash{$key}"; printf("var1 = $var1\n"); my $var2 = "aaa/$test_hash{${test}_bar}"; printf("var2 = $var1\n");

I receive the following error:

> ./braces_inside_braces.pl Bareword found where operator expected at ./braces_inside_braces.pl li +ne 14, near "${test}_bar" (Missing operator before _bar?) syntax error at ./braces_inside_braces.pl line 14, near "${test}_bar" Execution of ./braces_inside_braces.pl aborted due to compilation erro +rs.

The curly braces around "test" are required to separate it from "_bar", which is not part of the variable name, yet they are conflicting with the outer curly braces of test_hash. Is there any way to write that on one line without syntax errors, or do I have to use the method shown in the first case where I use the intermediate variable $key?

Replies are listed 'Best First'.
Re: curly braces inside of curly braces
by Fletch (Bishop) on Feb 04, 2022 at 19:02 UTC

    The problem is that you've used not-word-characters (and I may be wording (heh) that wrong) inside the braces of a hash access making it parse as an expression instead of a bareword string. You don't need to use an intermediary, but you need to properly quote your key "string" so that it's a valid expression instead, like $test_hash{ qq{${test}_bar} } for example.

    Addendum: just as you couldn't have my $foo = ${test}_bar; you'd instead need my $foo = "${test}_bar"; because the former isn't a simple bareword (but you could do my $bar = test_bar (so long as the subs strict-ness isn't in effect)).

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: curly braces inside of curly braces
by LanX (Saint) on Feb 04, 2022 at 19:26 UTC
    While the hash is string-interpolated, is the hash-key inside an executed expression!

    And ${test}_bar is not a valid expression.

    Debugger demo:

    DB<28> sub EXPR { print "executed" } DB<29> " $hash{ EXPR() } " executed DB<30> ${test}_bar Bareword found where operator expected at ...

    So multiple ways to do it are:

    use strict; use warnings; my %test_hash = ("foo_bar" => "baz"); my $test = "foo"; my $key = "${test}_bar"; my $var1 = "aaa/$test_hash{$key}"; print("var1 = $var1\n"); my $var2 = "aaa/$test_hash{ $test . '_bar' }"; # concat operator print("var2 = $var2\n"); my $var3 = "aaa/$test_hash{ qq(${test}_bar) }"; # qq() inside "" print("var3 = $var3\n"); my $var4 = qq(aaa/$test_hash{ "${test}_bar" }); # "" inside qq() print("var4 = $var4\n");

    var1 = aaa/baz var2 = aaa/baz var3 = aaa/baz var4 = aaa/baz

    And since you introduced printf

    my $var5 = sprintf 'aaa/%s', $test_hash{ "${test}_bar" }; # inside-o +ut print("var5 = $var5\n");

    update

    On a side note: Another good reason why perl-strings and here-docs are not a safe template syntax.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

      Nested paired delimiters also work:

      c:\@Work\Perl>perl use strict; use warnings; my %test_hash = ("foo_bar" => "baz"); my $test = "foo"; my $var5 = qq{aaa/$test_hash{ qq{${test}_bar} }}; # qq{} in qq{} print "var5 = '$var5' \n"; ^Z var5 = 'aaa/baz'


      Give a man a fish:  <%-{-{-{-<

        I agree a surfeit of curlies or any other delimiter can cause visual indigestion, but I wanted to use as many as possible to drive the point home in the example. :)

        Update: Oops... I meant this to be a reply to LanX's post.


        Give a man a fish:  <%-{-{-{-<

        Yeah true, their delimiters can be nested, but I'd chose other one(s) to avoid being distracted by other curlies like in ${test}

        qq(aaa/$test_hash{ qq(${test}_bar) });

        and readability is why I kept " in the first place

        qq(aaa/$test_hash{ "${test}_bar" });

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

Re: curly braces inside of curly braces
by talexb (Chancellor) on Feb 05, 2022 at 18:36 UTC

    Brother LanX hit the nail on the head already -- the debugger is your friend. Not sure about some syntax? Try it in the debugger first. Or run your script in the debugger, and all will be revealed. Turn "It can't be doing that!" into "Holy Cow -- it really is doing that!"

    Alex / talexb / Toronto

    Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.