http://qs321.pair.com?node_id=285498

Perl Idioms Explained - ${\$obj->method} and @{[sort @list]}

use constant MATCHES => join '|' => qw/ a list of words /; sub method { return "something complex here" } my $obj = bless []; my %hash = qw/ this is a hash /; print "it's a hash - @{[ %hash ]}\n"; print "method result - ${ \$obj->method }\n"; print "a regexp object - ", qr[\b (?: ${\MATCHES} ) \b]x, $/; __output__ it's a hash - this is a hash method result - something complex here a regexp object - (?x-ism:\b (?: a|list|of|words ) \b)
At times you'll want to add something more complex to an interpolated quote-like than a simple variable, but the option of simply concatenating isn't always available (i.e here docs, qr//), or perhaps, desired. So what one can do is take advantage of the perl's ${} and @{} syntax. Given the above examples I'll explain how this can be done.
print "it's a hash - @{[ %hash ]}\n";
The notable part of the above statement is @{[ %hash ]}. Here we're creating an anonymous array containing the elements of the aptly named hash %hash. Now that we have an array reference the @{} will dereference it and the resulting array will be interpolated into the string. Simple as that!
print "method result - ${ \$obj->method }\n";
As you can probably guess what we're interested in is ${ \$obj->method }. Firstly, we call the method on an object in the standard fashion - $obj->method, then we create a reference to what has just been returned and finally we dereference the newly created reference and the resulting scalar is interpolated.
print "a regexp object - ", qr[\b (?: ${\MATCHES} ) \b]x, $/;
While the above may look more complex it's just the same as the previous example, but surrounded by a regexp string constructor. In this case we're looking at ${\MATCHES} which calls the constant MATCHES, this returns a string which we create a reference to, then promptly dereference and interpolate into the string, and just like that we have a constant in a regex!

Caveats

One must be careful with the ${\foo} because if foo returns something that isn't a simple scalar value then you might get unexpected results. Also keep in mind that this is different from passing in a simple bareword which is largely used to distinguish between variable names and the surrounding text.

Summary

A shortcut for interpolating the return of complex expressions into a string.

_________
broquaint

Replies are listed 'Best First'.
Re: Perl Idioms Explained - ${\$obj->method} and @{[sort @list]}
by Juerd (Abbot) on Aug 21, 2003 at 16:31 UTC

    It's important to know that simple string concatenation is more efficient, and often much easier to read.

    "method result - ${ \$obj->method }\n"; "method result - " . $obj->method . "\n";
    An explicit join on space or $" is more efficient than using @{[]}.
    "foo @{[ some_list() ]}."; "foo ${\ join $", some_list() }"; "foo ${\ join ' ', some_list() }"; "foo " . join ' ', some_list();
    Easiest to read imho is (s)printf.
    printf "method result - %s\n", $obj->method;

    The idiom is also explained in perlfaq4's How do I expand function calls in a string?.

    Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

      I agree strongly. While broquaint's writeup is valuable in explaining these idioms, I don't think it's meant to encourage their use. You've demonstrated several simpler (and better imho) alternatives.

      Agreed. There is just one occasion where I really like having this idiom handy: here docs. Stuffing a map (or two, or three) inside a heredoc by way of this idiom is a neat poor man's templating engine.

      Makeshifts last the longest.

Re: Perl Idioms Explained - ${\$obj->method} and @{[sort @list]}
by Abigail-II (Bishop) on Aug 21, 2003 at 15:58 UTC
    One must be careful with the ${\foo} because if foo returns something that isn't a simple scalar value then you might get unexpected results.

    To be more precise, the \ operator gives its argument list context, which may surprise many people (it did me). The other interpolation construct @{[  ]} also provides list context. This is something to be aware of, and use of scalar will be appropriate in some cases, including in ${\scalar foo}.

    Abigail

      To be more precise, the \ operator gives its argument list context, which may surprise many people (it did me).

      Why would this surprise you? :)

      If I ask for a reference to an array that contains ('foo', 'bar', 'baz'), I expect a reference to an array that has three elements in it, not the number 3 (as would be the case if \ provided scalar context for its arguments.)

        Read Arrays are not lists and Scalars, Lists, and Arrays and repeat to yourself three times - "('foo', 'bar', 'baz') is not an array" ;-)

        I'm with Abigail-II. The \ operator has lots of weird cases that surprise you. For example:

        \@foo # reference to array @foo \(@foo, $a) # list of reference to array @foo and scalar $a \(@foo) # list of references to contents of @foo
        That doesn't explain it. \('foo', 'bar', 'baz') is the same as (\'foo', \'bar', \'baz'). Taking a reference to an array certainly doesn't behave that way.

        Makeshifts last the longest.

Re: Perl Idioms Explained - ${\$obj->method} and @{[sort @list]}
by Jenda (Abbot) on Aug 21, 2003 at 21:04 UTC

    Why does noone mention Interpolation.pm?

    use Interpolation '=' => 'eval'; print "5 + 6 = $={5+6}\n"; print "a regexp object - ", qr[\b (?: $={MATCHES()} ) \b]x, $/; use Interpolation '/' => sub {'$' . $Interpolation::builtin{commify}-> +(@_)}; print "The total is $/{530 * 12.25}\n"; use Interpolation 'S:$$*->$' => 'sprintfX'; print <<"*END*"; dfg sdfg sdfg wearg sdfhg esrg dsf sdf dfg $S{'%.2f %03d'}{37.5}{42} dfgdfg sdfg sdfgsdfg *END* # ouch. I just found a bug in the module. # for this to work you either have to get version newer than 0.69 # or change the 'sprintfX' to 'sprintfx' on line 51 of Interpolation.p +m :-(

    Jenda
    Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
       -- Rick Osborne

    Edit by castaway: Closed small tag in signature

Re: Perl Idioms Explained - ${\$obj->method} and @{[sort @list]}
by dbwiz (Curate) on Aug 21, 2003 at 16:50 UTC

    More things that you can put inside @{[]} .

    #!/usr/bin/perl -w use strict; use Data::Dumper; my $complex = { a => [ 1, 2, 3 ], b => [ { x => 1, y => 2, z => 3 }, 'alpha', [qw(even more nested ) +] ], c => { one => [qw(more value)] } }; # a function result print "@{[ eval 'Data::Dumper->Dump([$complex ],[q{complex} ])' ]}"; # a list print "@{[ ('aa'..'at') ]}\n"; # a list generated by a Regex print "@{[ 'hello Perl!' =~ /./g ]}\n"; # a list from a filehandle { local $/; print "@{[ <DATA> ]}\n"; } # (update) or simply print "@{[ <DATA> ]}\n"; # a list from globbing print "@{[ <*.pm> ]}\n"; __DATA__ This is text from DATA

    This would be the resulting output (The *.pm files depend on your current dir, of course).

    $complex = { 'a' => [ 1, 2, 3 ], 'b' => [ { 'x' => 1, 'y' => 2, 'z' => 3 }, 'alpha', [ 'even', 'more', 'nested' ] ], 'c' => { 'one' => [ 'more', 'value' ] } }; aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at h e l l o P e r l ! This is text from DATA Basename.pm CheckTree.pm Compare.pm Copy.pm DosGlob.pm Find.pm Path.pm + Spec.pm stat.pm Temp.pm

      local $/; print "@{[ <DATA> ]}\n";

      Sure, you CAN do that.

      • Creates an array
      • Fetches the file contents
      • Puts that in the new array, as one element
      • Copies the array element
      • Throws the array away
      • Adds \n
      • Passes a large string to print
      And it's a lot of work. print while <DATA>; or something similar is usually a MUCH better idea.

      Rule of thumb: do not use the idioms explained in the root of this thread, unless you really have to interpolate (like in regexes, although (??{}) may be a better idea). Especially the array creating one.

      Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

Re: Perl Idioms Explained - ${\$obj->method} and @{[sort @list]}
by xChauncey (Scribe) on Aug 22, 2003 at 02:39 UTC

    Since we don't see too many responses from novices to broquaint's "Perl Idioms Explained" posts, I'd like to publicly provide a viewpoint.

    You can get so much from things like perldoc and the O'Reilley books on Perl. However there are some times when I am learning Perl where I find my inner voice sounding like a little kid in math class. ("When will I ever use this?"). Now don't get me wrong, since I am learning Perl voluntarily, the inner voice doesn't sound as sullen/petulant as that kid, and I know that things that I (seemingly involuntarily) think that way about will turn out to be some of the most usefull tools at my disposal, but it is things like this post that make me go back and re-read the books and documentation on Perl until I own the concepts, that make me truly learn (and love) Perl.

    I'd just like to give a public thanks to broquaint, and to the excellent monks who expand on these posts, who really help me (and many others, I'm sure) along in my quest for Perl knowledge.

    Off I go to re-read ch.8 in my copy of the Camel, with what you all have provided in mind...(hmmm, I've always thought I was a pretty quick learner, but the fact that I have already worn out the book, considering my level of proficiency, reminds me that nothing worthwile is easy.)

    Thanks again

    C
Re: Perl Idioms Explained - ${\$obj->method} and @{[sort @list]}
by ambrus (Abbot) on Oct 20, 2014 at 10:47 UTC

    I've just seen a variant of this operator, the twin baby cart, "@{[...]}[...]" come up in golf. The original context is the golf task http://golf.shinh.org/p.rb?hello+hello+world where it's used by the winner perl entries by tails and tybalt89.

    This combines list slice indexing with interpolation of the baby cart operator, and is particularly useful because the array interpolation makes sure spaces (the default value of $") are added between the items. An example is:

    "@{[zero,one,two,three,four,five]}[3,1,4,1,5]"
    has the result "three one four one five".