Stile d'indentazione

regole usate nell'indentazione del codice

Lo stile d'indentazione in programmazione informatica è un insieme di regole per la gestione dell'indentazione dei blocchi di codice. Nella maggior parte dei linguaggi, detti in forma libera, l'indentazione non ha un significato sintattico ma viene usata come notazione secondaria per migliorare la leggibilità del codice, rendendo immediatamente visibile al programmatore la struttura dei blocchi che costituiscono il flusso di esecuzione del programma. Alcuni linguaggi di programmazione, come Python o Haskell, usano l'indentazione a livello sintattico per determinare i blocchi senza l'uso di parentesi (off-side rule), per cui in tali linguaggi l'indentazione non è solo una questione stilistica, ma un elemento sintattico a tutti gli effetti.

Tabulazioni, spazi e ampiezza dell'indentazioneModifica

L'ampiezza usata nell'indentazione è tipicamente dipendente dallo stile. Agli albori della programmazione era comune l'utilizzo di tabulazioni per indentare il codice, in quanto permetteva di risparmiare caratteri e ridurre la dimensione dei sorgenti. Nei sistemi Unix la tabulazione era tipicamente equivalente a otto caratteri, mentre su Macintosh e Microsoft Windows era tipicamente quattro, creando confusione quando i sorgenti venivano trasferiti e visualizzati su sistemi differenti. Gli editor moderni consentono di impostare l'ampiezza della tabulazione e di formattare tabulazioni e spazi automaticamente secondo le impostazioni.

Il mondo della programmazione è diviso nella scelta tra tabulazioni e spazi, che analogamente alla guerra degli editor costituisce una perenne "guerra di religione". Alcuni programmatori, come Jamie Zawinski[1] sostengono che la scelta degli spazi migliori la portabilità del codice tra ambienti e piattaforme differenti, mentre altri, come gli sviluppatori della piattaforma WordPress, sostengono l'opposto[2]. Nella edizione 2015 del Stack Overflow Developer Survey, il 45% dei partecipanti si è espresso a favore delle tabulazioni, contro il 33,6% a favore degli spazi.[3]

Aspetti praticiModifica

Visibilità dei blocchiModifica

I programmatori che fanno affidamento alle parentesi per trovare a colpo d'occhio i blocchi possono essere penalizzati da stili che collocano le parentesi al termine della istruzione precedente, mentre programmatori che si affidano maggiormente all'indentazione possono preferire questi stili in quanto generano blocchi più compatti verticalmente.

In alcuni casi può diventare difficile mantenere traccia visuale dell'estensione dei blocchi di codice, specie in grandi sezioni di codice con molte istruzioni composite annidate, che generano molti livelli di indentazione, che portano le estremità dei blocchi fuori dal campo visivo dell'editor e fanno perdere l'orientamento. Questo può essere sintomo di scarsa qualità del codice ed eccessiva complessità ciclomatica, da correggere tramite refactoring, scomponendo le funzioni troppo grandi in diverse funzioni più piccole e leggibili. Analogamente, un elevato numero di livelli di indentazione può spostare il codice a destra e renderlo poco leggibile, ed è tipicamente anch'esso sintomo della necessità di refactoring. Ad esempio, il manuale di stile del kernel Linux raccomanda un refactoring quando il codice supera i tre livelli di indentazione.[4]

Un modo per migliorare la leggibilità in alcuni casi consiste nell'aggiungere commenti che specificano a quale istruzione la parentesi chiusa faccia riferimento, con lo svantaggio di dover mantenere però testo duplicato.

for (int i = 0; i < total; i++) {
    foo(bar);
} // For (i)
if (x < 0) {
   bar(foo);
} // If (x < 0)

Molti editor permettono di individuare facilmente le parentesi corrispondenti tramite evidenziazione o animazioni quando si passa il cursore su una parentesi, o colorando differentemente ogni coppia di parentesi corrispondenti. Vim consente, tramite il tasto %, di saltare da una parentesi alla sua corrispondente.[5] La maggior parte degli editor inoltre supporta il folding dei blocchi, permettendo di mostrarne o nasconderne il contenuto secondo necessità.

Inserimento di istruzioniModifica

Alcuni stili prevengono errori in caso di inserimento di istruzioni in posizione errata. Ad esempio, inserendo erroneamente una istruzione tra un'istruzione di controllo come for o while e la successiva parentesi graffa di apertura del corrispondente blocco, il risultato è che solo la nuova istruzione viene effettivamente iterata, mentre il blocco viene eseguito solo una volta al termine delle iterazioni.

for (int i = 0; i < 10; i++)
    whoops(bar);   /* Inserimento nella posizione sbagliati, viene ripetuta 10 volte */
{
    only_once();   /* Questo blocco dovrebbe essere ripetuto 10 volte, ma viene eseguito una volta sola */
} // For (i) <-- Questo commento non è più valido, e diventa ingannevole

Gli stili che collocano le parentesi aperte al termine della riga dell'istruzione di controllo cui fanno riferimento prevengono tale problema.

Strumenti automaticiModifica

Sono disponibili strumenti per la formattazione automatica del codice secondo le preferenze di indentazione del programmatore, come il comando indent, presente in molti sistemi Unix-like.

Emacs fornisce diversi comandi per gestire l'indentazione, tra i quali l'indentazione automatica quando si inserisce un ritorno a capo (electric indent), la semplice pressione del tasto tab per indentare la riga corrente, e "M-x indent-region" per indentare ampie porzioni di codice. A seconda delle impostazioni, Emacs può anche sostituire gli spazi di indentazione con tabulazioni, eventualmente seguite da spazi, per ridurre al minimo il numero di caratteri.[6]

Vim permette di definire regole di indentazione specifiche per ogni linguaggio, applicandole poi automaticamente durante la scrittura del codice. Consente inoltre di selezionare l'uso di spazi o di tabulazioni per l'indentazione e di convertire automaticamente una selezione di codice secondo le impostazioni correnti tramite il comando :retab, nonché di riformattare e reindentare una selezione di codice tramite la pressione del tasto = in modalità visuale.

La "tabulazione elastica" (elastic tabstops) è uno stile di tabulazione che consente di mantenere automaticamente allineati interi blocchi di codice quando viene alterato il rientro di una singola linea che fa parte del blocco stesso, e richiede il supporto da parte dell'editor di testo.

Stili di indentazioneModifica

Stile K&RModifica

Lo stile K&R, che prende il nome da Brian Kernighan e Dennis Ritchie, autori di The C Programming Language, è comunemente usato nella programmazione in C e derivati. Il libro in realtà non specifica un proprio stile esplicitamente, ma lo segue coerentemente. Una nota specifica:

(EN)

«The position of braces is less important, although people hold passionate beliefs. We have chosen one of several popular styles. Pick a style that suits you, then use it consistently.»

(IT)

«La posizione delle parentesi è meno importante, sebbene la gente abbia forti convinzioni. Noi abbiamo scelto uno tra i diversi stili popolari. Scegli uno stile che si adatta a te, e usalo coerentemente.»

(Brian Kernighan e Dennis Ritchie, The C Programming Language)

La parentesi graffa di apertura del corpo di una funzione si trova sulla riga successiva all'header della funzione, sullo stesso livello di indentazione dell'header, mentre per i blocchi si trova sulla stessa linea dell'istruzione cui fa riferimento, preceduta da uno spazio. Le rispettive parentesi di chiusura si trovano su una nuova riga, allo stesso livello di indentazione della parentesi di apertura corrispondente o della relativa istruzione. Nel caso la parentesi chiusa sia seguita da una keyword else o while, quest'ultima si trova sulla stessa riga.

int main(int argc, char *argv[])
{
    ...
    while (x == y) {
        something();
        somethingelse();

        if (some_error) {
            do_correct();
        } else {
            continue_as_usual();
        }
    }

    finalthing();
    ...
}

Stile kernelModifica

Lo stile kernel è una variante del K&R usata estensivamente nei sorgenti del kernel Linux. Linus Torvalds raccomanda fortemente ai contributori di attenersi ad esso. Una descrizione dettagliata dello stile (che non riguarda solo l'indentazione, ma copre anche le convenzioni per la scelta degli identificatori, commenti e altri aspetti) è disponibile su kernel.org.[7]

Lo stile impiega tabulazioni (di lunghezza pari a otto caratteri) per l'indentazione. Le parentesi graffe aperte nelle definizioni di funzione si collocano su una nuova riga, mentre in tutti gli altri casi, ad esempio nei blocchi, si trovano sulla stessa riga di apertura dell'istruzione, precedute da uno spazio. Le label di uno switch sono allineate con il blocco che le racchiude. Un blocco costituito da una singola riga non deve essere racchiuso da parentesi graffe ma, nel caso un altro ramo della stessa istruzione lo richieda (ad esempio in un if-else), allora tutti i rami devono essere racchiusi da parentesi graffe. La lunghezza delle righe è limitata a 80 caratteri.

int power(int x, int y)
{
        int result;

        if (y < 0) {
                result = 0;
        } else {
                for (result = 1; y; y--)
                        result *= x;

        }
        return result;
}

1TBSModifica

I sostenitori di questo stile si riferiscono talvolta ad esso come "the one true brace style"[8] (abbreviato in 1TBS o OTBS). La differenza principale con lo stile K&R consiste nel fatto che le parentesi graffe non vengono omesse nei blocchi costituiti da una sola riga. I sorgenti del kernel Unix[9] adottano questo stile.

In questo stile, i costrutti che permettono l'inserimento di nuove righe di codice sono su righe separate, mentre quelli che lo proibiscono sono sulla stessa riga, in modo che l'inserimento di una nuova riga in qualsiasi posizione sia "sicuro", ovvero l'inserimento accidentale in una posizione indesiderata conservi comunque la coerenza tra flusso di esecuzione e indentazione.

//...
    if (x < 0) {
        puts("Negative");
        negative(x);
    } else {
        puts("Non-negative");
        nonnegative(x);
    }

Sebbene i programmi Java siano usualmente formattati secondo altri stili, esiste una certa quantità di codice Java formattato secondo varianti minori dello stile K&R (con la parentesi aperta sulla stessa riga nelle dichiarazioni di classi e metodi), principalmente per via delle guide linea stilistiche originariamente specificate da Sun Microsystems[10][11][12] e adottate in buona parte della Java Class Library. È anche uno stile popolare in ActionScript e JavaScript, insieme allo stile Allman.

StroustrupModifica

Lo stile Stroustrup è un adattamento fatto da Bjarne Stroustrup dello stile K&R per il linguaggio C++, impiegato nei suoi libri Programming: Principles and Practice using C++ e The C++ Programming Language.[13]

A differenza dell'originale, Stroustrup non posiziona l'else sulla stessa riga della parentesi di chiusura che lo precede[13]

    if (x < 0) {
        puts("Negative");
        negative(x);
    }
    else {
        puts("Non-negative");
        nonnegative(x);
    }

Stroustrup estende lo stile K&R per le classi, senza indentare le label public:, private: e analoghe. Mentre la parentesi di apertura del corpo di una funzione si trova sulla stessa riga dell'header, nel caso di una classe si trova sulla riga seguente. Inoltre, funzioni molto brevi possono essere scritte in un'unica riga.

    class Vector { 
    public:
        Vector(int s) :elem(new double[s]), sz(s) { }   // Construct a Vector
        double& operator[](int i) { return elem[i]; }   // Element access: subscripting
        int size() { return sz; } 
    private:
        double elem[lowast];    // Pointer to the elements
        int sz;                 // The number of elements
    };

Stile AllmanModifica

Lo stile Allman prende il nome da Eric Allman. È anche noto come "stile BSD" perché Allman scrisse molte utility per BSD Unix, ma differisce dallo stile BSD KNF. Le parentesi graffe di apertura associate ad una istruzione di controllo del flusso si trovano su una nuova riga, allo stesso livello di indentazione dell'istruzione, mentre le istruzioni nel blocco hanno un livello maggiore di indentazione.

while (x == y)
{
    something();
    somethingelse();
}

finalthing();

Questo stile è analogo a quello usato comunemente in Pascal e Transact-SQL, dove le parentesi sono ovviamente sostituite dalle keyword begin e end.

(* Esempio di indentazione Allman in Pascal *)
procedure dosomething(x: integer, y: integer)
begin
    while x = y do
    begin
        something;
        somethingelse
    end
end

Tra i supposti vantaggi di questo stile, vi sono il fatto che il codice indentato è chiaramente separato dall'istruzione che lo contiene, allo stesso tempo rendendo facile l'identificazione delle coppie di parentesi corrispondenti, rendendo più semplice la sostituzione o il commento delle istruzioni di controllo, e il posizionamento delle parentesi graffe per funzioni e blocchi è coerente.

Ad esempio, il seguente frammento è valido:

// While (x == y)
{
    something();
    somethingelse();
}

analogamente al seguente:

// For (int i=0; i < x; i++)
// While (x == y)
if (x == y)
{
    something();
    somethingelse();
}

o al seguente, che fa uso della compilazione condizionale:

    int c;
#ifdef HAS_GETCH
    while ((c = getch()) != EOF)
#else
    while ((c = getchar()) != EOF)
#endif
    {
        do_something(c);
    }

Una variante, chiamata Allman-8, utilizza colonne di 80 caratteri e indentazione a 8 spazi.

Stile BSD KNFModifica

Noto anche come Kernel Normal Form, è lo stile usato nella maggior parte del codice del sistema operativo BSD. Sebbene destinato principalmente al codice kernel, è ampiamente usato anche nel codice userspace. È fondamentalmente una variante accuratamente documentata dello stile K&R, usata nei sorgenti delle versioni 6 e 7 di UNIX dei Bell Labs.[14]

Il kernel e il software userland di SunOS usano uno stile simile,[14] anch'esso basato sulla documentazione di stile AT&T, al quale si fa talvolta riferimento come Bill Joy Normal Form.[15] Le linee guida SunOS furono pubblicate nel 1996. La correttezza dell'indentazione può essere verificata tramite l'utility cstyle.[16]

La tabulazione hard, usata per l'indentazione dei blocchi (ts in vim) è di 8 colonne, e quella soft (usata per la continuazione di righe multiple, sw in vim) di 4. Le chiamate di funzione non prevedono uno spazio prima delle parentesi, che deve essere invece inserito se la parentesi tonda è preceduta da una keyword come if, while, do, switch e return. Le funzioni che non dichiarano variabili locali devono lasciare una riga vuota dopo la parentesi di apertura del blocco che costituisce il corpo della funzione.

while (x == y) {
        something();
        somethingelse();
}
finalthing();

 

if (data != NULL && res > 0) {
        if (JS_DefineProperty(cx, o, "data",
            STRING_TO_JSVAL(JS_NewStringCopyN(cx, data, res)),
            NULL, NULL, JSPROP_ENUMERATE) != 0) {
                QUEUE_EXCEPTION("Internal error!");
                goto err;
        }
        PQfreemem(data);
} else {
        if (JS_DefineProperty(cx, o, "data", OBJECT_TO_JSVAL(NULL),
            NULL, NULL, JSPROP_ENUMERATE) != 0) {
                QUEUE_EXCEPTION("Internal error!");
                goto err;
        }
}

 

static JSBool
pgresult_constructor(JSContext *cx, JSObject *obj, uintN argc,
    jsval *argv, jsval *rval)
{

        QUEUE_EXCEPTION("PGresult class not user-instantiable");

        return (JS_FALSE);
}

Stile WhitesmithsModifica

Lo stile Whitesmiths, chiamato anche stile Wishart, era usato nella documentazione del primo compilatore C commerciale. Era popolare anche nel primo periodo dello sviluppo per Windows, in quanto venne adottato da tre importanti pubblicazioni, Programmer's Guide to Windows di Durant, Carlson e Yao, Programming Windows di Petzold, e Windows 3.0 Power Programming Techniques di Norton e Yao.

Insieme allo stile Allman, lo stile Whitesmiths è considerato il più comune nel Jargon File.[17]

La parentesi di apertura di un blocco di un'istruzione di controllo si trova su una nuova riga, e le parentesi sono indentate allo stesso livello del contenuto del blocco.

while (x == y)
    {
    something();
    somethingelse();
    }

finalthing();

Un esempio:

if (data != NULL && res > 0)
    {
    if (!JS_DefineProperty(cx, o, "data", STRING_TO_JSVAL(JS_NewStringCopyN(cx, data, res)),
                           NULL, NULL, JSPROP_ENUMERATE))
        {
        QUEUE_EXCEPTION("Internal error!");
        goto err;
        }
    PQfreemem(data);
    }
else if (!JS_DefineProperty(cx, o, "data", OBJECT_TO_JSVAL(NULL),
        NULL, NULL, JSPROP_ENUMERATE))
    {
    QUEUE_EXCEPTION("Internal error!");
    goto err;
    }

Stile GNUModifica

Analogamente agli stili Allman e Whitesmiths, lo stile GNU colloca le parentesi graffe in righe a sé, indentate di due spazi (ad eccezione delle definizioni di funzione, dove non sono indentate),[18] e il contenuto del blocco ha due ulteriori spazi di indentazione rispetto alle parentesi.

Reso popolare da Richard Stallman e raccomandato nei GNU Coding Standards, è stato probabilmente influenzato dal suo background di programmazione Lisp.[19] Nelle definizioni di funzioni, la parentesi di apertura della lista di argomenti è preceduta da uno spazio.

static char *
concat (char *s1, char *s2)
{
  while (x == y)
    {
      something ();
      somethingelse ();
    }
  finalthing ();
}

[18]

Questo stile combina i vantaggi di Allman e Whitesmiths, evitando il possibile svantaggio delle parentesi indistinte dal blocco che contengono. Uno svantaggio è legato allo "spreco" dovuto all'uso di due livelli di indentazione, uno dedicato alle sole parentesi, per indentare quello che logicamente è un singolo blocco.

Steve McConnell, nel suo libro Code Complete, esprime contrarietà a questo stile, considerato dannoso per la leggibilità del codice.[20]

Stile HorstmannModifica

Nell'edizione 1997 di Computing Concepts with C++ Essentials, Cay S. Horstmann usa una variante dello stile Allman con la prima istruzione di ogni blocco collocata sulla stessa riga della parentesi di apertura.

while (x == y)
{   something();
    somethingelse();
    //...
    if (x < 0)
    {   printf("Negative");
        negative(x);
    }
    else
    {   printf("Non-negative");
        nonnegative(x);
    }
}
finalthing();

Questo stile unisce i vantaggi dello stile Allman al fatto di risparmiare una riga per ogni blocco. L'edizione 2003 del libro è passata tuttavia all'uso dello stile Allman. [2]

Stile PicoModifica

Stile usato principalmente in Pico dai suoi progettisti:

stuff(n):
{ x: 3 * n;
  y: doStuff(x);
  y + x }

Condivide molti aspetti dello stile K&R, e tra i vantaggi, il posizionamento delle parentesi in apertura e chiusura è maggiormente coerente.

Stile BannerModifica

Lo stile banner colloca le parentesi di chiusura su una nuova riga, allo stesso livello di indentazione del blocco che racchiudono.

function1 () {
  do stuff
  do more stuff
  }

function2 () {
  etc
  }

In HTML:

<table>
  <tr>
    <td> lots of stuff...
      more stuff
      </td>
    <td> alternative for short lines </td>
    <td> etc. </td>
    </tr>
  </table>

<table>
  <tr> ... etc
  </table>

Stile LispModifica

Nello stile Lisp le parentesi chiuse sono tutte accodate al termine della riga dell'ultima istruzione che le precede. Questo elimina buona parte di righe di sole parentesi (che in linguaggi come Lisp sarebbero altrimenti molto abbondanti), ma fa si che l'indentazione rimanga l'unico modo per distinguere visualmente i blocchi annidati.

 ;; In Lisp
 (dotimes (i 10)
   (if (evenp i)
       (do-something i)
       (do-something-else i)))
 // In C
 for (i = 0; i < 10; i++) {
     if (i % 2 == 0) {
         doSomething(i); }
     else {
         doSomethingElse(i); } }
 # In Python
 for i in range(10):
     if i % 2 == 0:
         do_something(i)
     else:
         do_something_else(i)

Stile RatliffModifica

C. Wayne Ratliff propone nel suo libro Programmers at Work[21] uno stile simile a 1TBS, ma con la parentesi di chiusura allo stesso livello di indentazione del blocco che racchiude. Ratliff era il programmatore che ha lavorato all'implementazione originale di dBase-II e dBase-III, e indica lo stile come documentato originariamente nelle guide linea della Digital Research Inc.

 // In C
 for (i = 0; i < 10; i++) {
     if (i % 2 == 0) {
         doSomething(i);
         }
     else {
         doSomethingElse(i);
         }
     }

Compact control readability styleModifica

Questo stile colloca gli else su una riga differente rispetto alla parentesi graffa chiusa che li precede, con le parentesi di apertura sulla stessa riga dell'istruzione cui fanno riferimento.

// In JavaScript
if(x == y){
    doSomethingA();
    doSomethingB();
}
else{
    doSomethingC();
    doSomethingD();
}

NoteModifica

  1. ^ "Tabs versus Spaces: An Eternal Holy War." by Jamie Zawinski 2000
  2. ^ "WordPress Coding Standards"
  3. ^ Stack Overflow Developer Survey 2015, Stack Overflow.
  4. ^ Indentation, su Linux kernel coding style, kernel.org.
    «Now, some people will claim that having 8-character indentations makes the code move too far to the right, and makes it hard to read on a 80-character terminal screen. The answer to that is that if you need more than 3 levels of indentation, you're screwed anyway, and should fix your program.».
  5. ^ Linda Lamb, Learning the vi editor. O'Reilly
  6. ^ https://www.gnu.org/software/emacs/manual/html_node/emacs/Indent-Convenience.html
  7. ^ [1]
  8. ^ The Jargon File, su catb.org. URL consultato il 18 agosto 2014.
  9. ^ J. Lions, Unix Operating System Source Code Level Six (PDF), University of New South Wales, June 1977.
  10. ^ Achut Reddy, Java Coding Style Guide (PDF), Sun Microsystems, 30 marzo 2000. URL consultato il 30 maggio 2008 (archiviato dall'url originale il 28 febbraio 2006).
  11. ^ Java Code Conventions (PDF), Sun Microsystems, 12 settembre 1997. URL consultato il 30 maggio 2008 (archiviato dall'url originale il 13 maggio 2008).
  12. ^ Code Conventions for the Java Programming Language, Sun Microsystems, 20 marzo 1997. URL consultato il 30 maggio 2008.
  13. ^ a b Bjarne Stroustrup, PPP Style Guide (PDF), su stroustrup.com, September 2010.
  14. ^ a b Bill Shannon, C Style and Coding Standards for SunOS (PDF), Version 1.8 of 96/08/19., Sun Microsystems, Inc., 1996. URL consultato il 6 febbraio 2015.
  15. ^ Brendan Gregg, DTraceToolkit Style Guide, Brendan D. Gregg. URL consultato il 6 febbraio 2015.
  16. ^ Bill Shannon, cstyle 1.58 98/09/09, su https://www.illumos.org/projects/illumos-gate, Sun Microsystems, Inc.. URL consultato il 6 febbraio 2015.
  17. ^ The Jargon File 4.4.8: indent style, su catb.org. URL consultato il 31 marzo 2014.
  18. ^ a b Formatting Your Source Code, su GNU Coding Standards.
  19. ^ My Lisp Experiences and the Development of GNU Emacs (Transcript of Richard Stallman's Speech, 28 Oct 2002, at the International Lisp Conference), su gnu.org.
  20. ^ Steve McConnell, Code Complete: A practical handbook of software construction, Redmond, WA, Microsoft Press, 2004, pp. 746–747, ISBN 0-7356-1967-0.
  21. ^ Susan Lammers, Programmers at Work, Microsoft Press, 1986, ISBN 0-914845-71-3.

Collegamenti esterniModifica

  Portale Informatica: accedi alle voci di Wikipedia che trattano di informatica