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

I like to use sprintf whenever possible, to stitch strings together. I'm struggling to make nested code work inside sprintf. Can someone advise?
my $ordered_schema = sprintf( "%s%s", $header . "\n", sub { my $ordered_columns; for my $column (sort keys %columns) { $ordered_columns .= $columns{$column} . "\n"; } return $ordered_columns; }, );

Replies are listed 'Best First'.
Re: sprintf: using nested code
by BrowserUk (Patriarch) on Sep 14, 2015 at 18:49 UTC

    Try:

    my $ordered_schema = sprintf( "%s%s", $header . "\n", sub { my $ordered_columns; for my $column (sort keys %columns) { $ordered_columns .= $columns{$column} . "\n"; } return $ordered_columns; }->(), );

    Though this is simpler:

    my $ordered_schema = join "\n", $header, map $columns{ $_ } sort keys +%columns;

    You could also use:

    my $ordered_schema = sprintf( "%s%s", $header . "\n", do { my $ordered_columns; for my $column (sort keys %columns) { $ordered_columns .= $columns{$column} . "\n"; } $ordered_columns; ## Update: return statement removed. Thanks +Choroba. }, );

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.
    I'm with torvalds on this Agile (and TDD) debunked I told'em LLVM was the way to go. But did they listen!
      Thanks. Exactly what I needed.
Re: sprintf: using nested code
by 2teez (Vicar) on Sep 14, 2015 at 19:08 UTC

    Hi mhearse,
    I'm struggling to make nested code work inside sprintf. Can someone advise?
    1. My candy advise, DO NOT BE extremely CLEVER! Simply use your for loop outside the sprintf

    2. However, if you want to do want you want to do, because you are using perl, then instead of using a subroutine or an eval, why not use a do{...} like so: not REALLY tested

    #!/usr/bin/perl -w use strict; my %hash = ( son => { year => 2006, name => 'Paul', }, father => { year => 1981, name => 'Ryan', }, mother => { year => 1978, name => 'Bose', }, ); print sprintf( "%s: %s", 'Person' . $/, do { ## <== note here my $order; for ( sort keys %hash ) { $order .= join ' | ' => $_, %{ $hash{$_} }, $/; } $order; } );
    check perldoc -f do
    from your CLI to see why this over eval.

    3. IMHO, don't be too clever about your program. A simple program often save the day!

    UPDATE:
    Apparently, while I was still trying to frame my answer to this, BrowserUk came up first! ++!
    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me
Re: sprintf: using nested code
by afoken (Chancellor) on Sep 14, 2015 at 19:13 UTC
    I like to use sprintf whenever possible, to stitch strings together.

    Well, that begs for a web service! Create a JSON document from all of the strings that should be concatinated, encoded in base64, wrap that - uuencoded - into an XML file, and post that via SOAP to the web service. The web service should reply with a JSON document containing a base64 encoded XML document that contains the resulting string uuencoded. That way, you can waste even more CPU cycles.

    Why don't you just use the concat operator "." or join?

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      Thanks. A bold suggestion. If I had time, it would be fun to code.
Re: sprintf: using nested code
by Laurent_R (Canon) on Sep 14, 2015 at 18:52 UTC
    Please explain the problem you have.

    This works for me:

    $ perl -e 'sub double { return 2 * shift;} ; my $c = sprintf "%s\n%s\n +", "foo", double(3); print $c;' foo 6
      OK, I had originally missed that you are defining the sub inside the sprintf arguments (but never actually call the sub), so that sprintf will output a coderef, as in this simpler example:
      $ perl -e 'print sprintf( "%s%s", > "header" . "\n", > sub { return 3}); > ' header CODE(0x6000684c8)
      Of course, you can solve the problem by calling the coderef:
      $ perl -e 'print sprintf( "%s%s", "header" . "\n", ,sub { return 3}- +>())' header 3
      as shown by BrowserUk, but it seems to me that you are looking for complicated ways of achieving simple things.

      Why don't you define your sub separately? Or use some other way of merging your data?

      Something like that works properly:

      $ perl -e 'sub concat { my $str; for ($_[0]..$_[1]) { $str .= $_;} $st +r;} > print sprintf "%s\n%s\n", "foo", concat('a', 'e'); > ' foo abcde
Re: sprintf: using nested code
by mhearse (Chaplain) on Sep 14, 2015 at 17:47 UTC
    I found one solution using eval. Any additional comments are welcome:
    my $ordered_schema = sprintf( "%s%s", $header . "\n", eval { my $ordered_columns; for my $column (sort keys %columns) { $ordered_columns .= $columns{$column} . "\n"; } return $ordered_columns; }, );