Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options

No Hard Tabs in Code

by Xiong (Hermit)
on Jul 01, 2010 at 11:55 UTC ( [id://847496]=perlmeditation: 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 -

Replies are listed 'Best First'.
Re: No Hard Tabs in Code
by Jenda (Abbot) on Jul 01, 2010 at 13:02 UTC

    I would say "use spaces or use tabs, but don't mix 'em!" As long as you are consistent, you are fine. It's when you sometimes use a tab and sometimes N spaces when you run into problems. Or rather someone else with different size of tabs runs into problems.

    I prefer tabs for indenting code myself.

    Enoch was right!
    Enjoy the last years of Rome.

      I agree that consistency is important, but I think it's best that consistency extend to an entire team rather than being restricted to an individual coder.

      A problem arrises when working on a team without a set standard. While each individual might have their preference and stick to it, they're usually working on a file that has been through many hands, so you'll have a mix of tabs and spaces. And the space people could have 4 or 8 column tabs. So you wind up with code that's supposed to be on the same level of indentation prefixed with 4 spaces, 8 spaces, or a tab.

      I used to work at a place with defined coding standards - nothing passed review if it had the wrong bracket style, or if you had tabs instead of spaces, wrong variable naming format, etc. I thought it was rather draconian until I went to work for a place that had no standards whatsoever and saw what a mess things were. More that just aesthetic; it was diffictult to follow the code and figure things out when the indentation kept poping back in and out.

      That all being said, I'm a space guy who converted from tabs. For one, a space is a space no matter where you view it. I've got my editor configured to insert four spaces whenever I press tab.

Re: No Hard Tabs in Code
by MidLifeXis (Monsignor) on Jul 01, 2010 at 13:12 UTC

    There was a discussion in the CB the other day about this. The nearest concession I can make (I am a spaces person) is tabs at the beginning of the line to indent, and spaces to align after that.

    My editor manages the alignment for many types of indent / align, and C-M-\ reindents a region in the current indentation configuration. Backspace is not needed since tab realigns the current line as necessary.

    Set rules, let the tools follow them. Anything else is TooMuchWork(tm) ;-)


      The nearest concession I can make (I am a spaces person) is tabs at the beginning of the line to indent, and spaces to align after that.

      That isn't a concesssion; it's the only valid way.

      I'm very much a tab person. Tabs are for indenting. They're not for aligning. Indenting is a logical concept, aligning is a visual one. It doesn't matter what size your tabs are set to; N tabs at the start of a line are always the same size as N tabs at the start of the line, always smaller than N+1 tabs, and always larger than N-1 tabs. That's perfect for indenting.

      However, a tab is not the same size as any number of spaces, nor are tabs following something other than BOL or tab the same size as any other tabs. That's alignment; tabs aren't for that.

      (____ is a single tab. So is ----, for clarity.)

      ____if(x ____ && y) ____{ ____----print "some foo" ____---- . "some bar"; ____} ____struct foo ____{ ____----int xyz; ____----unsigned char *abc; ____}

      IMO, it's pretty obvious what's indentation and what's alignment. Using tabs for the latter, outside of very special cases, is a mortal sin.

        Specifically, using tabs to align defeats the purpose of using tabs. (You are no longer free to choose your preferred indentation distance)

        Using spaces to indent, on the other hand, is a bit like having a fixed width web page. It is the wrong size for the majority of people, but it is at least consistent.

        In a perfect world, everything would show tabs at your preferred width, people would not use tabs for alignment and everybody would see code in their own preferred style independent of the original coder. Indentation would be distinct from code. There could even be a way to indicate which curly brackets qualify for an optional linebreak plus indentation.

        But display/edit programs don't show properly, and people don't write properly. This is why we can't have nice things :P

        PS: Actually, this seems a lot like web pages... using tabs to align is as bad as using a 20% width object to align text. Just Doesn't Work.

        Using spaces everywhere is like perldoc's fixed width syndrome. Running a script to convert the indentation (bigger or smaller) is like having to write and apply a style override for the website. Makes it less convenient and uglier than it should be, but also more useful than the original state.

Re: No Hard Tabs in Code
by ssandv (Hermit) on Jul 01, 2010 at 15:53 UTC

    Use spaces because everything else is worse unless used with extreme caution, not because spaces are awesome. Perfectly tab-formatted code, in an environment where you know the tab stops will be the same for everyone, is probably the best case--but the instant someone grabs a code snippet and tosses it in an email message (5-space tabs...the horror!) or changes their settings, all that effort to line things up is not only for naught, it's actively harmful to reading the code.

    It's not that spaces are better, it's that they're least awful when awfulness happens (and it will.) Other people have to read your code, if you're at all serious about programming, and it's not excusable, nor effective to demand they conform to your tab stops. So don't use them.

      Someone setting a (e-mail) tab to 5 spaces is asking for horror. They deserve horror.

      IMHO anyone setting a TAB to something other than 8 spaces should not send patches or be able to commit to a central repo.

      I have no strong feelings for tab vs spaces. As long as they are used consistently within the team (teams are huge for open source projects), it is fine with me.

      I much more care about indentation. Specifically with people that use cut-n-paste from other files and do not adjust it for the current file. Oh horror!

      Enjoy, Have FUN! H.Merijn

        8 spaces is a ridiculous waste of real estate, to me. It's far too much for a single layer of indentation, and I find it _harder and slower to read_.

        On the other hand, if you mandate tabs, and tab stops are smaller than the most extreme person prefers them to be, you get the ultimate disaster of mixed tabs and spaces--which is yet another good reason to turn everything into spaces.

        A 5-space first tab, for paragraph indentation, was the standard for fixed width text for a very long time until not all that long ago. How quickly we forget.

Re: No Hard Tabs in Code
by GrandFather (Saint) on Jul 02, 2010 at 07:03 UTC

    Perl::Tidy - enough said. ;)

    True laziness is hard work

      Good lord, why not not turn put some oil on that fire? :)

      I had programmers that were prepared to roast me, because good forbid, we implement ANY standard layout conventions. They were horrified because it seemed to imply, that they did not know how to code, or be there were being restricted by the "MAN" (which was me, and WTF did I think I was!).

      That being said, it amazed me how personal some programmers took coding layouts.

Re: No Hard Tabs in Code
by Anonymous Monk on Jul 01, 2010 at 14:07 UTC

    I'm a spaces person. Sharing code among folks who's editors have different ideas on how big a tab should be have cured me.

    My current editor is set up to "Outdent" a line on Shift-Tab. Heck, I don't even need to have the cursor before the 1st printable character. This handles many of the OP's concerns.

    I've also bound perltidy for easy access within my editor. That and a well formed .perltidyrc file do wonders for maintaining order in my source.

    I have heard the occasional horror story about perltidy introducing bugs into code, but I've been using perltidy for quite some time on my own code, published obfuscations and published japhs (it really helps understand what these crazy folks are doing) with no ill effect. I do wonder what atrocities these story tellers were committing and what vintage of perltidy they were using....

      Shift-Tab does different stuff in Geany. When cursor is within leading indentation, it subtracts a level; it does this correctly whether cursor starts at a tab stop or not. When cursor is somewhere after the first printable char, it just moves the cursor back to the previous stop; it doesn't alter the line at all.

      But if Shift-Tab caused little green worms to crawl out of the window, I wouldn't use hard tabs anymore. Lesson learned.

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

      I have two .perltidyrc files.

      One contains just this line:

      The other contains various heretical statements such as
      -i=3 # Indent level is 3 cols -et=3 # Use tabs for indents because I'm such a sociopath -ci=3 # Continuation indent is 3 cols -icb # Make closing braces align with the body of their block

      As I'm editing code, I'll run perltidy over it with my preference for formatting. Before checking code back in, I'll run perltidy with the Perl Best Practices formatting, run ./Build test and commit.

      I, too, draw a distinction between "indenting" and "alignment". I, too, program in languages other than Perl (such as Ruby, Python and PHP).

      I also edit using a proportional font (DejaVu Sans is my current favourite), which renders any attempts at "alignment" futile. I cannot stand the practice of sticking in extra spaces to make the '=' symbols line up.

      The perltidy tool lets me slip in under the radar of contemporary society.

        Until you run into constructs that perltidy misformats. Then your coworkers will eventually wonder, every time they fix the use of & to override a prototype and then you touch unrelated code in the same source file, why the space gets re-inserted stupidly...

        Do you at least look at the differences you are introducing before you finish checking in? Probably not. Probably making merge conflicts significantly worse plenty of times as well.

        - tye        

Re: No Hard Tabs in Code
by Burak (Chaplain) on Jul 01, 2010 at 19:58 UTC
Re: No Hard Tabs in Code
by Anonymous Monk on Jul 02, 2010 at 06:43 UTC

    I used to work at a shop that had standardized on tabs. It is fine when all your co-workers are using the same standard. Any decent editor will give you lots of control over this sort of thing.

    One pointer that may be of interest to vim users. Turning on visual whitespace makes it much easier to avoid mixing tabs and spaces in the one file.

    In my .vimrc file:

    set list set listchars=tab:,trail:,extends:>,precedes:<

    displays both tabs and trailing spaces.

Re: No Hard Tabs in Code
by Argel (Prior) on Jul 01, 2010 at 16:58 UTC
    Nedit lets you Shift Left and Shift Right (shift+ctrl+9 and shift+ctrl+0 respectively), though this affects the entire line, so it's only a solution for beginning of the line indenting. Anyway, I think part of the answer to spaces vs. tabs is to use an editor that makes it easier to shift left and right instead of having to delete all of the spaces.

    Elda Taluta; Sarks Sark; Ark Arks

      Changing the indent level is rarely an issue. I have Increase Indent, Decrease Indent set to Ctrl-[, Ctrl-], because that's how BBEdit does it.

      Getting tokens internal to a line to start exactly on tab stops is sometimes a bit trickier, without using hard tabs. On the other hand, it's often more important to match orthogonal syntax to the previous line, so spaces are better there anyway. I'm sold.

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

        Getting tokens internal to a line to start exactly on tab stops is sometimes a bit trickier, without using hard tabs.

        I don't know what you mean. Not only does auto-indenting handle that in almost all situations, the tab key of my editors bring me to a tab stop (even though it's configured to do so by adding spaces).

Re: No Hard Tabs in Code
by ikegami (Patriarch) on Jul 01, 2010 at 17:29 UTC

    It's removing them that's been my major issue.

    That's what Shift-Tab is for.

Re: No Hard Tabs in Code
by SuicideJunkie (Vicar) on Jul 06, 2010 at 14:44 UTC
    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.

    Why would you refuse to distinguish between indentation and alignment even when you know what they are?.

    To put it simply, you indent blocks of code, and you align symbols (such as delimiters). If it doesn't matter whether it is 2,3,4,6 or 8 spaces, then it is indentation. If it has to be exactly N spaces then it is alignment.

    #indent (arbitrary distance) #\/ \/ while (... or ...) #/\ /|\ /\ #indent alignment (distance must be exactly length("while ("))

    If in doubt, run Perltidy with the -i=0 option. It will still add spaces for alignment, but not for indenting.

      I deliberately treat all horizontal whitespace alike today. Spaces only.

      It's just as well I don't make the distinction. If I did, I'd have to quibble with your definition. But I don't. "One char to rule them all."

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

        I fail to see what is so difficult about that definition. Indentation is logical spacing. Alignment is the visual spacing.

        TidyPerl knows the difference as shown above.

        Or, to use a heretical example, Python forces you to use only indentation, and forbids alignment.

        I don't think it gets much simpler than saying "The stuff you like to be 2 spaces wide but the guy sitting next to you likes to be 4 spaces wide". That's the indentation.

Re: No Hard Tabs in Code
by Lady_Aleena (Priest) on Jul 05, 2010 at 17:04 UTC

    Hello Xiong...

    I love my current text editor Notepad++ when it comes to tabination. Not only does it allow me to set the length of tabs (I use 2 spaces), it replaces the tabs with the spaces immediately. When I have to outdent a section of code, all I have to do is hit shift-tab, and even though I have spaces, the program knows what I really want, so I don't have to worry about the outdenting.

    All my code is nicely lined up with spaces, since it is the only way to guarantee that my code is the same wherever I post it. Notepadd++ makes my code all nice and portable. It always has a lot of pretty colors for my code. I like the pretty colors. :)

    Have a nice day!
    Lady Aleena
Re: No Hard Tabs in Code
by JavaFan (Canon) on Jul 05, 2010 at 15:36 UTC
    Most of my changes of indentation require zero keystrokes. My editor knows that if the previous line ends with a {, the next line should have an extra level of indent. And if I start a line with }, the indentation should be lowered by one level.

    If I want to shift a line, it requires two keystrokes: >> or <<. Three keystrokes to do two lines: 2>> or 2<<. Two keystrokes to do the rest of the paragraph, the rest of the screen, or the rest of the file: <}, <L or <G. Three for the next five paragraphs: <5}.

    Note that's quite independent of whether I use tabs or spaces for indentation. I've set up my editor to not insert tabs when hitting the tab key (but if I really want to, I can do ^V^I (two keystrokes)) - it will use spaces. But I seldomly have the need to use the tab key (well, unless in "command mode", then it cycles between visible buffers).

    Note that removing 4 internal spaces doesn't require 4 keystrokes: 4x or 4X will do. For multiple lines of code that need 4 spaces to be removed, I navigate to a corner of the rectangle, mark its place: ma, move to its opposite corner, and delete the block: d\a.

Re: No Hard Tabs in Code
by Brovnik (Hermit) on Jul 22, 2010 at 16:06 UTC
    I use an editor that :
    1. Converts tab to spaces on save (tabstop set to 2 == company standard)
    2. Tab indents by one tabstop
    3. Shift-tab outdents one tabstop.
    4. Auto-indent is ON for <current language>

    That's all you need, ever, no hard tabs.
    IMHO, any editor that doesn't/can't do that is broken.
    I often have code that is indented 8 levels and a line length of 150 chars total. Giving 8*8=64 chars to indent, rather than 8*2=16 seems crazy and would annoy me all day, every day. Edit: I also like aligning, particularly =, and/or, hash assignments and arguments, again using spaces for all for these. That's for eye appeal as much as readability.
    my $short = 5; my $longer = 6; my $wheels = { unicycle => 1, bike => 2, car => 4, }; if ( $a == 3 and $long_name == 4567 and $is_tuesday ) {

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://847496]
Approved by Corion
Front-paged by Corion
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (5)
As of 2024-04-23 18:03 GMT
Find Nodes?
    Voting Booth?

    No recent polls found