Istruzione Condizionale case in Object Pascal

Concetti Chiave
  • L'istruzione case in Object Pascal consente di selezionare uno tra molti percorsi di esecuzione basati sul valore di una singola espressione di tipo ordinale.
  • La sintassi generale dell'istruzione case include l'espressione da valutare, una serie di clausole con valori costanti e un'istruzione opzionale else per gestire i casi non previsti.
  • Le clausole dell'istruzione case possono includere più valori separati da virgole o intervalli di valori utilizzando la sintassi valoreInizio..valoreFine.
  • L'istruzione case migliora la leggibilità e la manutenibilità del codice rispetto a una serie di istruzioni if...then...else annidate.

Istruzione case

Vi sono casi in cui le istruzioni if possono diventare piuttosto complesse, specialmente quando si devono testare molti valori diversi di una singola variabile. In questi casi, l'uso di più clausole if...then...else, nonché di istruzioni else if annidate, può rendere il codice difficile da leggere e da manutenere.

Esiste un modo più semplice per gestire tali situazioni in molti linguaggi di programmazione, incluso Object Pascal. Questo metodo è l'istruzione case, che in altri linguaggi è nota come switch. L'istruzione case consente di selezionare uno tra molti percorsi di esecuzione in base al valore di una singola espressione. La restrizione, però, è che l'espressione deve essere di un tipo ordinale, come un intero, un carattere o un enumerato.

Un'istruzione case consiste di un'espressione usata per selezionare un valore e una lista di possibili valori, o un intervallo di valori. Questi valori sono costanti, e devono essere unici e di un tipo ordinale. Eventualmente, può esserci un'istruzione else che viene eseguita se nessuno dei valori specificati corrisponde al valore del selettore.

Mentre non c'è una specifica istruzione endcase, che termini la serie di valori, un case è sempre terminato da un end (che in questo caso non è un terminatore di blocco, dato che non c'è un begin corrispondente).

La sintassi generale di un'istruzione case in Object Pascal è la seguente:

case <espressione> of
  <valore1>: <istruzione1>;
  <valore2>: <istruzione2>;
  ...
  <valoreN>: <istruzioneN>;
else
  <istruzioneElse>;
end;
Nota

L'istruzione case richiede un valore ordinale

Creare un'istruzione case richiede un valore ordinale. Un'istruzione case basata su un valore stringa non è permessa. In quel caso è necessario usare istruzioni if annidate o una struttura dati diversa, come un dizionario che vedremo nelle prossime lezioni.

Ricapitolando:

Definizione

Istruzione condizionale case

Un'istruzione case consente di selezionare uno tra molti percorsi di esecuzione in base al valore di una singola espressione di tipo ordinale. La sintassi generale è la seguente:

case <espressione> of
  <valore1>: <istruzione1>;
  <valore2>: <istruzione2>;
  ...
  <valoreN>: <istruzioneN>;
else
  <istruzioneElse>;
end;

Dove:

  • <espressione> è un'espressione di tipo ordinale il cui valore determina quale ramo dell'istruzione case verrà eseguito.
  • <valore1>, <valore2>, ..., <valoreN> sono costanti uniche di tipo ordinale che rappresentano i possibili valori dell'espressione.
  • <istruzione1>, <istruzione2>, ..., <istruzioneN> sono le istruzioni o i blocchi di codice che verranno eseguiti se l'espressione corrisponde al rispettivo valore.
  • else è una clausola opzionale che specifica un'istruzione o un blocco di codice da eseguire se nessuno dei valori specificati corrisponde al valore dell'espressione.

Nel caso in cui l'espressione non corrisponda a nessuno dei valori elencati, e non sia presente una clausola else, l'istruzione case non eseguirà alcuna azione.

Esempio

Vediamo un primo semplice esempio di utilizzo dell'istruzione case.

Vogliamo scrivere un programma che, dato in ingresso un numero intero compreso tra 1 e 10, restituisca il corrispondente nome in italiano del numero. Se il numero non è compreso tra 1 e 10, il programma deve restituire un messaggio di errore.

Se volessimo implementare questo programma usando le istruzioni if, potremmo scrivere qualcosa del genere:

program ConvertiNumero;

var
    numero: Integer;
    nomeNumero: string;
begin
    Write('Inserisci un numero intero tra 1 e 10: ');
    ReadLn(numero);

    if numero = 1 then
        nomeNumero := 'uno'
    else if numero = 2 then
        nomeNumero := 'due'
    else if numero = 3 then
        nomeNumero := 'tre'
    else if numero = 4 then
        nomeNumero := 'quattro'
    else if numero = 5 then
        nomeNumero := 'cinque'
    else if numero = 6 then
        nomeNumero := 'sei'
    else if numero = 7 then
        nomeNumero := 'sette'
    else if numero = 8 then
        nomeNumero := 'otto'
    else if numero = 9 then
        nomeNumero := 'nove'
    else if numero = 10 then
        nomeNumero := 'dieci'
    else
        nomeNumero := 'Errore: il numero non è compreso tra 1 e 10';

    WriteLn('Il numero in italiano è: ', nomeNumero);
end.

Come si può notare, il codice risulta piuttosto lungo e difficile da leggere a causa delle numerose clausole if...then...else.

Possiamo riscrivere lo stesso programma utilizzando l'istruzione case, ottenendo un codice più compatto e leggibile:

program ConvertiNumero2;

var
    numero: Integer;
    nomeNumero: string;
begin
    Write('Inserisci un numero intero tra 1 e 10: ');
    ReadLn(numero);

    case numero of
        1: nomeNumero := 'uno';
        2: nomeNumero := 'due';
        3: nomeNumero := 'tre';
        4: nomeNumero := 'quattro';
        5: nomeNumero := 'cinque';
        6: nomeNumero := 'sei';
        7: nomeNumero := 'sette';
        8: nomeNumero := 'otto';
        9: nomeNumero := 'nove';
        10: nomeNumero := 'dieci';
    else
        nomeNumero := 'Errore: il numero non è compreso tra 1 e 10';
    end;

    WriteLn('Il numero in italiano è: ', nomeNumero);
end.

Il risultato è lo stesso, ma il codice è più chiaro ed è facilmente modificabile. Ad esempio, se volessimo aggiungere il numero 11, basterebbe aggiungere una sola riga all'interno dell'istruzione case:

11: nomeNumero := 'undici';

Intervalli e Valori Multipli

L'istruzione case in Object Pascal supporta anche l'uso di intervalli di valori e la specifica di più valori per un singolo ramo.

Per specificare più valori per un singolo ramo, si possono separare i valori con una virgola. Ad esempio:

case <espressione> of
    valore1, valore2: <istruzione>;
    { ... }
end;

Mentre per specificare un intervallo di valori, si usa la sintassi valoreInizio..valoreFine. Ad esempio:

case <espressione> of
    valoreInizio..valoreFine: <istruzione>;
    { ... }
end;

Vediamo un esempio che utilizza entrambe queste funzionalità:

program ClassificaCarattere;

var
    carattere: Char;
    tipoCarattere: string;
begin
    Write('Inserisci un carattere: ');
    ReadLn(carattere);

    case carattere of
        'a', 'e', 'i', 'o', 'u': tipoCarattere := 'Vocale';
        'b', 'c', 'd', 'f', 'g',
        'h', 'j', 'k', 'l', 'm',
        'n', 'p', 'q', 'r', 's',
        't', 'v', 'w', 'x', 'y',
        'z':                     tipoCarattere := 'Consonante';
        '0'..'9':                tipoCarattere := 'Cifra';
    else
        tipoCarattere := 'Altro carattere';
    end;

    WriteLn('Il carattere inserito è: ', tipoCarattere);
end.

In questo esempio, l'istruzione case classifica il carattere inserito come vocale, consonante, cifra o altro carattere, utilizzando sia valori multipli che un intervallo. Per le vocali e le consonanti, sono stati specificati più valori separati da virgole, mentre per le cifre è stato utilizzato un intervallo.

Ricapitolando:

Definizione

Clausole con valori multipli e intervalli per l'istruzione case

In un'istruzione case, è possibile specificare più valori per un singolo ramo separandoli con una virgola, oppure definire un intervallo di valori utilizzando la sintassi valoreInizio..valoreFine. Ad esempio:

case <espressione> of
    valore1, valore2: <istruzione>;
    valoreInizio..valoreFine: <istruzione>;
    { ... }
end;
Nota

Clausole ripetute non permesse

Un'importante restrizione nell'uso dell'istruzione case è che ogni valore o intervallo di valori può apparire una sola volta. Non è permesso avere clausole ripetute. Ad esempio, il seguente codice non è valido:

case <espressione> of
    1: <istruzione1>;
    1: <istruzione2>; // Errore: clausola ripetuta
    2..5: <istruzione3>;
    3..7: <istruzione4>; // Errore: intervallo sovrapposto
end;

Quindi, bisogna assicurarsi che ogni valore o intervallo sia unico all'interno dell'istruzione case e che gli intervalli non si sovrappongano.

In ogni caso, il compilatore di Object Pascal segnalerà un errore se si tenta di utilizzare clausole ripetute o intervalli sovrapposti.

Clausola else

È considerata buona pratica includere la parte else per segnalare una condizione indefinita o inaspettata. Un'istruzione case in Object Pascal seleziona un percorso di esecuzione, non effettua un salto. In altre parole, esegue l'istruzione o blocco dopo i due punti del valore selezionato e salta all'istruzione dopo il case.

Questo è molto diverso da ciò che accade in linguaggio C (e alcuni dei suoi linguaggi derivati) che trattano i rami di un'istruzione switch come salti ed eseguiranno tutte le istruzioni seguenti a meno che non si usi specificamente una richiesta break (anche se questo è uno scenario specifico in cui Java e C# differiscono realmente nella loro implementazione).

La clausola else è simile al blocco default in C, Java e C#. Serve a gestire i casi in cui il valore dell'espressione non corrisponde a nessuno dei valori specificati nei rami precedenti.

Ricapitolando:

Definizione

Clausole else nell'istruzione case

La clausola else in un'istruzione case viene eseguita se nessuno dei valori specificati corrisponde al valore dell'espressione.

Essa è opzionale. In sua assenza, se l'espressione non corrisponde a nessuno dei valori elencati, l'istruzione case non eseguirà alcuna azione.

La sintassi è la seguente:

case <espressione> of
    <valore1>: <istruzione1>;
    <valore2>: <istruzione2>;
    ...
    <valoreN>: <istruzioneN>;
else
    <istruzioneElse>;
end;

Blocchi di codice nelle istruzioni case

Negli esempi precedenti, ogni ramo dell'istruzione case eseguiva una singola istruzione. Tuttavia, è possibile eseguire più istruzioni per un singolo ramo racchiudendole tra begin ed end.

In altre parole, possiamo adoperare istruzioni composte all'interno di un ramo case.

Ad esempio:

case <espressione> of
    valore1: begin
                 <istruzione1>;
                 <istruzione2>;
                 ...
               end;
    valore2: begin
                 <istruzione1>;
                 <istruzione2>;
                 ...
               end;
    { ... }
end;

Ecco un esempio che mostra come utilizzare un blocco di codice in un ramo case:

program EsempioCaseConBlocchi;

var
    giorno: Integer;
    nomeGiorno: string;
begin
    WriteLn('Inserisci un numero intero tra 1 e 7');
    WriteLn('dove 1 = Lunedì, 2 = Martedì, ..., 7 = Domenica: ');
    ReadLn(giorno);

    case giorno of
        1: begin
               nomeGiorno := 'Lunedì';
               WriteLn('Inizio della settimana lavorativa.');
           end;
        2: begin
               nomeGiorno := 'Martedì';
               WriteLn('Secondo giorno della settimana.');
           end;
        3: begin
               nomeGiorno := 'Mercoledì';
               WriteLn('Metà settimana!');
           end;
        4: begin
               nomeGiorno := 'Giovedì';
               WriteLn('Quasi alla fine della settimana.');
           end;
        5: begin
               nomeGiorno := 'Venerdì';
               WriteLn('Ultimo giorno lavorativo!');
           end;
        6: begin
               nomeGiorno := 'Sabato';
               WriteLn('Finalmente il weekend!');
           end;
        7: begin
               nomeGiorno := 'Domenica';
               WriteLn('Giorno di riposo.');
           end;
    else
        begin
            nomeGiorno := 'Errore: il numero non è compreso tra 1 e 7';
            WriteLn(nomeGiorno);
        end;
    end;

    if giorno in [1..7] then
        WriteLn('Il giorno della settimana è: ', nomeGiorno);
end.

In questo esempio, ogni ramo dell'istruzione case contiene un blocco di codice racchiuso tra begin ed end, che esegue più istruzioni. Se l'utente inserisce un numero non compreso tra 1 e 7, viene eseguito il blocco else, che gestisce l'errore.