Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??

Indent with spaces, not tabs. Perl Best Practices (Conway 2005 p20)

Conway converted me from an 8-column-tab-man to 4 columns but he could not dissuade me from hard tabs. I'm aware that his is the majority opinion and I was willing to convert from tabs to spaces whenever making my code obviously public. But I said, It can do no harm in code that only I see.

My argument in favor of hard tabs is that I really like things to line up. I don't just entab; I delete existing tabs, frequently. A little spasm goes through my fingers when I see a section of code where a lot of stuff is all lined up nicely -- but not on a tab stop! Also, I'm annoyed when outdenting if I must hit the backspace key four times per tab stop.

My editor of choice, Geany, is very good about this but not perfect. Given:

line1 line2

...a single backspace keystroke will fix line2. But:

a line1 a line2

... requires four keystrokes. There's the risk that, if one is shortening a line not to match the previous line but in some anticipation, one will end up with, say, a trailing comment not on a tab stop.

In case you're among the unconverted, let me say that most editors will allow you to set the tab key to produce as many spaces as are needed to bring you up to the next tab stop. It's removing them that's been my major issue.

But, also, for the multiple space insertion to work correctly, one must position the cursor correctly at the start of the following token. Otherwise, the spaces between the cursor and the token are gleefully pushed out -- the correct number of spaces are inserted to position the cursor, not the text. My old fingers tend to wobble a bit and I end up clicking one space off; and there, it's messed up.

I have filtered my code before posting on PerlMonks or pastebin; I have accepted funky output from various shell commands that insist on antique 8-column tabs. I felt the price not too little to pay.

Conway encourages his readers to think for themselves and not blindly follow his injunctions; so I did.


My current work on a source filter has me running generated code through the Perl debugger. With hard tabs in my code, dumps look like this:

DB<8> y caller_id assertion report_code $assertion = '$x < \'1\'' $caller_id = 1 $report_code = " unless(\$x < '1') {\cI\cI\cI\cI\cI\cI\cI\cI \cISmart +::Comments::Any::Warn_for( \cI\cI\cI\cI\cI\cI\cI\cI\cI\cI \cI\cI\cI1, + \cI\cI\cI\cI\cI\cI\cI\cI \cI\cI\"\\n\", \cI\cI\cI\cI\cI\cI\cI\cI\cI +\cI \cI\cI\cIq{### \$x < '1' was not true} \cI\cI\cI\cI \cI\cI);\cI\c +I\cI\cI\cI\cI\cI\cI\cI\cI\cI\cI \cI Smart::Comments::Any::Dump_for(\ +cI\cI\cI\cI\cI\cI\cI \cI-caller_id\cI=> 1,\cI\cI \cI-prefix\cI\cI=> + q{ \$x was:},\cI \cI-varref\cI\cI=> [\$x], \cI\cI\cI \cI-no_new +line\cI=> 1\cI\cI\cI\cI );\cI\cI\cI\cI\cI\cI\cI\cI\cI;\cI\cI\cI\cI\c +I\cI\cI \cI die \"\\n\"\cI\cI\cI\cI\cI\cI\cI\cI\cI\cI\cI\cI\cI\cI\cI +\cI }\cI\cI\cI\cI\cI\cI\cI\cI\cI\cI\cI\cI\cI"

Trimming off the trailing tabs doesn't fix it, either; tabs internal to the code are still escaped in this peculiar and unreadable fashion. Geany will convert a whole source file from tabs to spaces -- correctly -- but there's no obvious way to convert just the code generation strings. Find-and-replace from 1 tab to 4 spaces fails, since each tab represents a variable amount of spaces.

Having had it demonstrated for all time that I was wrong, I'm now sold. No hard tabs in code: none.


My need to be sure I'm lining up on tab stops is still strong. My workaround is in the form of this scratch snippet:

# --- TAB STOPS --- 1 1 1 1 1 1 1 1 + 1 1# # 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 + 8 9# # | | | | | | | | | | | | | | | | | + | |#

This may look wrong onscreen but it's exactly 78 columns wide. It can be pasted anywhere in code to check if all is correct.


Some Monks have fallen into the error of hard tabs "only for indentation". Indenting is a logical concept but it is not always clear what is indentation and what is spacing internal to the line. Consider this (abbreviated) real example:

1: # This is not a subroutine but a call to Filter::Simple::FILTER 2: # with its single argument being its following block. 3: # 4: FILTER { 5: ##### |--- Start of filter ---| 6: ##### @_ 7: 8: # Assertions... 9: s{ ^ $hws* $intro [ \t] $check : \s* (.*?) $optcolon $hws* $ } 10: { _decode_assert($caller_id, $1) }egmx; 11: 12: # Undocumented feature: 13: # # Anything else is a literal string... 14: # s{ ^ $hws* $intro $hws* (.*) } 15: # {Dump_for(-prefix=>q{$1});$DBX}gmx; 16: 17: #~ say "---| Source after filtering:\n", $_, '|--- END SOURCE CODE +'; #~ 18: 19: }; 20:

My interpretation:

  • 1..2 are a block comment, (part of) the introduction to the whole block. 1 is, in some sense, flush left; 2 is a continuation line, therefore indented one level. (Effectively, though, only 2 spaces.)
  • 4 begins the block and really is flush left.
  • 5..6 are smart comments; when this is run with use Smart::Comments '#####', these are filtered into code executing within the block. Therefore they are indented one level.
  • 8 is a paragraph comment introducing 9..10. Therefore it is indented equally. 9 is the match of a filtering rule. 10 is the replacement, therefore an extra space is inserted to align left delimiters; which is still indentation.
  • 13..15 is a filtering rule that has been semi-permanently disabled with the disabling comment at 12. If it were re-enabled, then it would be indented exactly as 8..10.
  • 17 is a debugging-print statement, temporarily disabled. If re-enabled, it will be flush left, so it can be noticed easily and again disabled.
  • 7, 11, 16, 18 are blank lines internal to the block; therefore they are pre-indented (with four spaces) in anticipation of further editing. (And yes, some would say these must be removed at some time.)
  • 20 is a blank line external to the block; therefore it contains nothing except a newline.

Which of these can/should be replaced by hard tabs? I say none.

- the lyf so short, the craft so long to lerne -

In reply to No Hard Tabs in Code by Xiong

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or or How to display code and escape characters are good places to start.
Log In?

What's my password?
Create A New User
Domain Nodelet?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (4)
As of 2021-10-20 19:46 GMT
Find Nodes?
    Voting Booth?
    My first memorable Perl project was:

    Results (82 votes). Check out past polls.