http://www.perlmonks.org?node_id=1228138

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

I would like to use perltidy but I cannot quite wrap my head around how continuation indentation works when it comes to certain statements.

Formatting the lines

if ($foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $quuxq +uuxquuxquuxquux) { foo(); }
with perltidy using the default options of -l=80 -i=4 -ci=2, I would expect the program to output
if ( $foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $quuxquuxquuxquuxquux ) { foo(); }
However, the actual result is
if ( $foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $quuxquuxquuxquuxquux ) { foo(); }
That is, perltidy is breaking up the first line and indenting it with four spaces (actually, the number of spaces specified by the -i option) instead of two spaces. I have searched the ChangeLog of perltidy (which is otherwise very helpful in explaining changed behavior of the program) for an explanation but I haven't found other than that something seems to have changed between 2001 06 17 and 2001 10 16 which have the following, respectively:
if ($bigwasteofspace1 && $bigwasteofspace2 || $bigwasteofspace3 && $bigwasteofspace4) { bigwastoftime(); } if ( $opt_d || $opt_m || $opt_p || $opt_t || $opt_x || ( -e $archive && $opt_r ) ) { ( $pAr, $pNames ) = readAr($archive); }

My first thought was that perltidy is aligning the expression with the opening paren, but that does not seem to be the case, as replacing if with while yields

while ($foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $quuxquuxquuxquuxquux ) { foo(); }

It may be noted that perltidy does not insert a space after the opening paren despite the the manual's claim that spaces within containers are always symmetric. In fact, while -pt=2 will remove the space before the closing paren, not even -pt=0 will insert a space after the opening paren.

Why is perltidy using indent-columns instead of continuation-indentation and why is the tightness not symmetric in these particular cases? What is it that I fail to understand? Is continuation-indentation used only for certain long lines and not for others?

  • Comment on Why is perltidy using indent-columns instead of continuation-indentation when breaking up a long if-line?
  • Select or Download Code

Replies are listed 'Best First'.
Re: Why is perltidy using indent-columns instead of continuation-indentation when breaking up a long if-line?
by LanX (Archbishop) on Jan 07, 2019 at 15:47 UTC
    Perltidy is from my experience a beautiful but difficult beast. *

    The product is mostly awesome but details are very hard to predict and tune.

    If I were you I'd take a look into the test suite and file a bug report if your case is misinterpreted.

    There is a Tk gui on CPAN to interactively try out options, but it was pretty hard to install.

    In the end I'm personally just relying on Emacs indentation and formatting of my code, while using perltidy to decipher foreign products.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

    *) avoiding any classic cliché "jokes" about women here ;)))

      > If I were you I'd take a look into the test suite and file a bug report if your case is misinterpreted.

      Being new to the game, I am a bit hesitant to attribute any differences between my expectations and the actual result to a bug rather than to my own incomplete understanding.

Re: Why is perltidy using indent-columns instead of continuation-indentation when breaking up a long if-line?
by Lotus1 (Vicar) on Jan 07, 2019 at 19:25 UTC

    From the Perltidy documentation section 'Controlling whether perltidy breaks before or after operators':

    By default, perltidy breaks after these token types: % + - * / x != == + >= <= =~ !~ < > | & = **= += *= &= <<= &&= -= /= |= >>= ||= //= .= % += ^= x= And perltidy breaks before these token types by default: . << >> -> && + || //

    The way I understand it is the -ci option lets you specify what happens to lines that are only broken because they are too long. Your example will break before the && not because of line length.(See corrections in the following nodes) From the documentation:

    Code Indentation Control
    -ci=n, --continuation-indentation=n
    Continuation indentation is extra indentation spaces applied when a long line is broken. The default is n=2, illustrated here:

    my $level = # -ci=2 ( $max_index_to_go >= 0 ) ? $levels_to_go[0] : $last_output_level;

    I also found a line in the documentation that mentions a debug file. This also prints a .LOG file which gives details about the length of the lines and any warnings. "Also try the -D flag on a short snippet of code and look at the .DEBUG file to see the tokenization."

      > The way I understand it is the -ci option lets you specify what happens to lines that are only broken because they are too long. Your example will break before the && not because of line length.

      Are you sure about that? My understanding was that perltidy breaks lines for the very reason that they are too long and that lines will be broken before or after the operators in wbb and wba. Otherwise, should not a line like the following (or just about any line with any of the operators wbb/wba/baao/bbao operators) be broken as well?

      if ($foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz) { foo(); }

      As it is, such lines are not broken. Lines like the ones in my example are only broken if their length exceed the -l=80 boundary.

        >Are you sure about that? My understanding was that perltidy breaks lines for the very reason that they are too long ...

        I misspoke about that part. But I was on the right track. The thing I missed before is that indentation is treated differently if there is a long expression inside parentheses. There is also a difference if all the operators in an expression are the same. The examples below show what I mean. It seems to be working consistently. Have you tried running it on a large chunk of code to see how different situations are handled?

        testtidy.pl

        if ($foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $bazba +zbazbazbaz) { foo1(); } if ($foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz) { foo2(); } $foofoofoofoofoo = "abcdef ghijklmnop" . "abcdef ghijklmnop"; $foofoofoofoofoo = "abcdef ghijklmnop" . "abcdef ghijklmnop" . "abcdef + ghijklmnop"; $foofoofoofoofoo = "abcdef ghijklmnop" . "abcdef ghijklmnop" . "abcdef + ghijklmnop" . "abcdef ghijklmnop"; my $level1 = ( $max_index_to_go >= 0 ) ? $levels_to_go_12345[0] : $las +t_output_level_12345; my $level2 = ( $max_index_to_go >= 0 ) ? $levels_to_go_1234567890[0] : + $last_output_level_1234567890; while ($foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $ba +zbazbazbazbaz) { 1; } while ("abcdef ghijklmnop" . "abcdef ghijklmnop" . "abcdef ghijklmnop" + . "abcdef ghijklmnop") { 1; } ($foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $bazbazba +zbazbaz || $123456) || $bazbazbazbazbaz; ($foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $bazbazba +zbazbaz && $123456) || $bazbazbazbazbaz;

        When I run perltidy -l=80 -i=4 -ci=2 testtidy.pl it produces this:

        if ( $foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $bazbazbazbazbaz ) { foo1(); } if ( $foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz ) { foo2(); } $foofoofoofoofoo = "abcdef ghijklmnop" . "abcdef ghijklmnop"; $foofoofoofoofoo = "abcdef ghijklmnop" . "abcdef ghijklmnop" . "abcdef ghijklmnop"; $foofoofoofoofoo = "abcdef ghijklmnop" . "abcdef ghijklmnop" . "abcdef ghijklmnop" . "abcdef ghijklmnop"; my $level1 = ( $max_index_to_go >= 0 ) ? $levels_to_go_12345[0] : $last_output_le +vel_12345; my $level2 = ( $max_index_to_go >= 0 ) ? $levels_to_go_1234567890[0] : $last_output_level_1234567890; while ($foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $bazbazbazbazbaz ) { 1; } while ( "abcdef ghijklmnop" . "abcdef ghijklmnop" . "abcdef ghijklmnop" . "abcdef ghijklmnop" ) { 1; } ( $foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $bazbazb +azbazbaz || $123456 ) || $bazbazbazbazbaz; ( $foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $bazbazbazbazbaz && $123456 ) || $bazbazbazbazbaz;

        Edit: Here's one more example using a lot of parentheses. testtidy2.pl:

        (($foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $bazbazb +azbazbaz || $12345678901234567890) && $test112345123456789 ) && $test +22222233333 || $bazbazbazbazbaz || $bazbazbazbazbaz123456 && $bazbazb +azbazbaz123456789 || (($x1122334441234512345 && $x2211123451345 % $x3 +3112212345123451234 && $y111222123451234512345 || $y11122222123451234 +5 ) && ($x1234512345123456789 || $x12345612345123456789 || $x12356712 +3451234567890 && $x1234123412345 )) || $xx1122331234512345 && $xx1231 +231234512345;

        I compared running perltidy.pl with the default options and with your options and it gave the same output. If it used the continuing line spacing inside parentheses I don't think it would be as clear as this.

        ( ( $foofoofoofoofoo && $barbarbarbarbar && $bazbazbazbazbaz && $bazbazbazbazbaz || $12345678901234567890 ) && $test112345123456789 ) && $test22222233333 || $bazbazbazbazbaz || $bazbazbazbazbaz123456 && $bazbazbazbazbaz123456789 || ( ( $x1122334441234512345 && $x2211123451345 % $x33112212345123451234 && $y111222123451234512345 || $y111222221234512345 ) && ( $x1234512345123456789 || $x12345612345123456789 || $x123567123451234567890 && $x1234123412345 ) ) || $xx1122331234512345 && $xx1231231234512345;
Re: Why is perltidy using indent-columns instead of continuation-indentation when breaking up a long if-line?
by karlgoethebier (Monsignor) on Jan 07, 2019 at 20:29 UTC

    If i were in your shoes i wouldn‘t waste my time with questions like this.

    And BTW: Did you try to format the code by hand and then run perltidy on the buffer/file?

    Big surprise! O.K. - sometimes...

    Best regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

      I can come up with many reasons why you want to put time and effort into this!

      For the purpose of the this discussion, let us assume I have taken over the module the OP wrote years ago, and for good reason, he/she put up for grabs (no more interest in Perl, no more access to required resources, left life, ...).

      Now, for obvious reasons, I do *not* like the style/layout of the code this module was (consistently) written in, and - also for this discussion - the module has thousands of lines of code.

      I think that code needs to be easy to *read* in order to be able to maintain it properly, so next to *consistent* indentation and styling, it needs to be beautiful and that is where perltidy drops in place.

      Whatever style the module's code was written in, I run perltidy with *my* preferences, and suddenly all the code looks beautiful, so I can understand it. Next step is to edit all the code by hand and make the last mis-formats match my own style. As no software is perfect, there will be parts that are not formatted according taste.

      By browsing/editing the codebase, I now get acquainted by the code's structure and main parts and I can start focusing on open issues and bugs.

      By having a .perltidyrc file that formats the code to as close as possible what you think is best (and we will not agree there), you will save yourself a lot of time later on.


      Enjoy, Have FUN! H.Merijn
      > If i were in your shoes i wouldn‘t waste my time with questions like this.

      I am not sure what you mean when you say questions like this. Is my question not appropriate for perlmonks?

      > And BTW: Did you try to format the code by hand and then run perltidy on the buffer/file?

      Yes. I did and the result was that perltidy disagreed with me and increased my two spaces to four.

        Is my question not appropriate for perlmonks?

        Your question is very appropriate for PerlMonks - the way I interpreted karlgoethebier's point was "don't worry too much about things that are too difficult to change" ;-) Although I do think it's worth it to investigate a bit how difficult it is to change this behavior. Personally I agree with LanX, I tend to format my own code by hand or via the editor's built-in tools and to leave perltidy for cleaning up code I get from elsewhere. But if you want to run perltidy on everything that's fine too, although AFAIK not every bit of its behavior is configurable.

        Edit: Typos.