in reply to How do I read this line of code?

This adds a string to $buff. In fact, it adds several things: a newline, $level-1 spaces and the first element of @pre_push, that is removed from the array. It is equivalent to
for my $string ("\n", ' ' x ( $level - 1 ), shift @pre_push) { $buff = $buff . $string; }

Replies are listed 'Best First'.
Re^2: How do I read this line of code?
by Tux (Canon) on Sep 29, 2011 at 09:33 UTC

    TIMTOWTDI. I would never use a for loop for this, but it might well be a simplification of what in earlier versions warranted the for loop.

    $buff .= $_ for "\n", ' ' x ( $level - 1 ), shift @pre_push; => { my $indent = " " x ($level - 1); $buf .= "\n" . $indent . shift @pre_push; } or $buff .= "\n" . (" " x ($level - 1)) . shift @pre_push; or $buff .= join "" => "\n", " " x ($level - 1), shift @pre_push; or $buff .= join ((" " x ($level - 1)) => "\n", shift @pre_push); or ...

    Enjoy, Have FUN! H.Merijn

      Okay, this clarifies a lot, so there is no real need for a for loop.

      The for loop is not used to loop through the elements of the array, but rather to loop through the things we want to add to $buff being:

      1. a newline
      2. spaces
      3. the entire content of the array
Re^2: How do I read this line of code?
by Anonymous Monk on Sep 29, 2011 at 09:32 UTC

    Thanks for your answer, this helps a lot.

    Now, what if there is no shift:

    $buff .= $_ for "\n", '  ' x ( $level - 1), @pre_push;

    I would expect every element in @pre_push to have a newline and spaces in front of it, but when I test it, using the following code, I see that the newline and spaces are only added once.

    my @pre_push; my $level = 2; my $buff = ''; push (@pre_push, "test"); push (@pre_push, "test2"); for my $string ("\n", ' ' x ( $level - 1 ), @pre_push) { $buff = $buff . $string; } print $buff;

    Output:

      testtest2

      The for (used as a statement modifier) in the original line of code takes a list which consists of three entries: newline, some number of spaces, and an item shifted off an array. If you remove the shift the last entry in the list becomes another list (the elements in the array) appended to the list containing the first two items. There is nothing there to prefix each element following the first two elements of the list with the concatenation of the first two elements which is what your expectation implies.

      If you want to achieve that you have to rewrite the statement a little. Consider:

      my @pre_push = qw(test test2); my $level = 2; my $buff = ''; $buff .= $_ for map {"\n" . (' ' x ($level - 1)) . $_} @pre_push; print $buff;

      Prints:

      test test2

      The map concatenates the prefix to each element of the array before passing the modified list on to the for.

      Alternatively you could move the prefix concatenation to the assignment to the left of the for to give the same result and remove the map:

      $buff .= "\n" . (' ' x ( $level - 1)) . $_ for @pre_push;
      True laziness is hard work
      The loop iterates over the newline, spaces and the array. If you want to iterate it over the array and add newlines fore each member of the array, you can do
      $buff .= "\n" . (' ' x ($level - 1)) . $_ for @pre_push;