Někdo preferuje mezery, někdo tabelátory. Diskuse o tom, který způsob je lepší, bývají nekonečné, protože každý z nich má své pro a proti a každý programátor to vidí jinak, takže to nemá smysl řešit. V následujícím článku bych však chtěl argumentovat, proč není dobrý nápad v kódu tabelátory a mezery mixovat.
Proč ne?
Protože velikost tabelátoru se liší editor od editoru a programátor od programátora. Typická nastavení bývají zobrazovat tabelátor jako 2, 4, či 8 mezer. Pokud mixujete mezery a tabelátory, tak se kód ve vašem editoru sice může zobrazovat korektně, ale jiný programátor uvidí nepořádek a pomyslí si o vás nepěkné věci.
Pojďme na příklad. Dejme tomu, že máte v editoru nastaveno, ať se vám tabelátor zobrazuje jako 4 mezery. Pak může kód, který mixuje tabelátory a mezery vypadat korektně (→
značí tabelátor):
→ if (shouldMove) { → → target->move(); → } else { target->standStill(); // Zde se k odsazení místo tabelátorů použily mezery. → }
Pokud má ale někdo nastaveno, ať se mu tabelátor zobrazuje jako 8 mezer, uvidí nepořádek:
→ if (shouldMove) { → → target->move(); → } else { target->standStill(); // Zde se k odsazení místo tabelátorů použily mezery. → }
Buďte proto svědomitý programátor a nemixujte mezery a tabelátory.
Jazyk Python je pak případ sám o sobě. Pokud v něm budete mixovat tabelátory a mezery, buď vám kód bude vyhazovat výjimku IndentationError
, nebo (hůř) bude fungovat, ale bude dělat něco jiného, než očekáváte (např. příkaz se přiřadí do jiného bloku, než vidíte v editoru). Důvodem je, že v Pythonu jsou oproti ostatním jazykům bílé znaky signifikantní ze syntaktického hlediska.
Odsazování pomocí tabelátorů, zarovnání pomocí mezer
Někteří programátoři mixují mezery a tabelátory tak, že k odsazení používají tabelátory a k zarovnání mezery. Příklad:
→ → collide(getFirstObjectInCollision(), → → getSecondObjectInCollision()); // Zde se k zarovnání použily mezery.
Tento kód se zobrazí korektně nezávisle na nastavení editoru. Je zde však jiný problém: při dalších úpravách, ať už autorem či jinými programátory se často zapomene či dojde k přehlédnutí, co se k odsazení a zarovnání použilo. Pokud pak jiný programátor změní název funkce a zarovná pomocí tabelátorů, nastane opět zmatek:
→ → collideTwoObjects(getFirstObjectInCollision(), → → → → getSecondObjectInCollision()); // Zde se mixují mezery a tabelátory.
Typicky totiž v editoru mezery a tabelátory nejsou vidět, takže se špatně rozlišuje, co je kde. Když si pak kód zobrazí někdo, u koho je tabelátor zobrazován jako 8 mezer, zobrazí se mu toto:
→ → collideTwoObjects(getFirstObjectInCollision(), → → → → getSecondObjectInCollision()); // Zde se mixují mezery a tabelátory.
Takže odsazování pomocí tabelátorů a zarovnání pomocí mezer taktéž nedoporučuji.
Zobrazení mixování mezer a tabelátorů v editoru
Abych se vyhnul neúmyslnému způsobování nepořádku při editaci kódu, tak mám ve Vimu nastaveno zvýraznění mixování mezer a tabelátorů:
" Highlight mixture of spaces and tabs au BufEnter * hi SpacesTabsMixtureGroup guibg=gray18 guifg=red ctermbg=gray ctermfg=red au BufEnter * match SpacesTabsMixtureGroup /^ \+\t\+\|^\t\+ \+/
Ukázka:
Dále mám ve Vimu na klávese F2
nastaveno zobrazení mezer, tabelátorů a konců řádků v kódu:
" Tell Vim which characters to show for expanded TABs, trailing whitespace, " ends of lines, and non-breakable space set listchars=tab:>-,trail:#,eol:$,nbsp:~,extends:>,precedes:< " F2: Toggle the display of unprintable characters nnoremap <silent> <F2> :set list!<CR>
Hodí se to, když se chci podívat, co přesně za bílé znaky (angl. white space) v kódu jsou:
Ukázka:
Když edituji cizí kód, tak si pomocí F2 zobrazím, co se k odsazení používá, nastavím si příslušně Vim a vesele edituji. Ve Vimu lze např. k odsazení používat pořád klávesu TAB
a nastavit si, zda vám má vložit tabelátor nebo ekvivalentní (nastavený) počet mezer. Lze tak pro každý jazyk/projekt použít speciální nastavení.
Další čtení
- What are the downsides of mixing tabs and spaces?
- Why do some people mix tabs and spaces in their code?
- Tabs versus spaces—what is the proper indentation character for everything, in every situation, ever?
- Python: Myths about Indentation
- Mixing tabs and spaces in Python
- Why tabs are clearly superior