Istruzione Condizionale if in Object Pascal

L'istruzione if, chiamata anche istruzione condizionale, permette di eseguire del codice solo nel caso in cui una condizione venga soddisfatta.

Quando la condizione specificata è soddisfatta, l'istruzione if permette di eseguire l'istruzione che segue la clausola then.

Esiste anche la possibilità, attraverso la tripletta if then else, di specificare un'altra istruzione che venga eseguita nel caso opposto, ossia quando la condizione non è soddisfatta.

In questa lezione vedremo la sintassi delle istruzioni if then e if then else. Vedremo, anche, come gestire casi più complessi in cui è necessario concatenare oppure innestare più istruzioni if tra di loro.

Istruzione condizionale if

La prima tipologia di istruzioni condizionali che studieremo sono le istruzioni if.

Un'istruzione if permette di eseguire una o più istruzioni solo nel caso in cui una certa condizione booleana è soddisfatta. Essa può essere usata anche per scegliere tra due alternative: eseguire un gruppo di istruzioni se la condizione è soddisfatta o, in caso negativo, eseguire un altro gruppo di istruzioni.

Nel primo caso si parla di istruzione if-then, mentre nel secondo caso di istruzione if-then-else.

Istruzione if then

Studiamo il primo tipo di istruzione if partendo da un semplice esempio di programma che determina se un numero intero introdotto dall'utente sia pari:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
program pari_o_dispari;

var
    X: Integer;
begin
    Write('Inserisci un numero: ');
    ReadLn(X);
    if (X mod 2) = 0 then
        WriteLn('Il numero inserito è pari');
end.

Nel programma dell'esempio, alla riga 8 andiamo a testare se il valore inserito dall'utente sia pari; in particolare, andiamo a controllare se X modulo 2 sia pari a zero. Quindi la condizione da soddisfare è:

(X mod 2) = 0

che è un'espressione booleana. Questa espressione è seguita dalla parola chiave then e dall'istruzione da eseguire in caso la condizione sia soddisfatta. In particolare, l'istruzione da eseguire nel caso in cui X sia pari è:

WriteLn('Il numero inserito è pari');

Quindi la sintassi dell'istruzione if è:

if condizione then
    istruzione;

Al posto di istruzione possiamo anche inserire istruzioni composte ricordandoci di racchiudere le sotto-istruzioni tra begin e end. Ad esempio, avremmo potuto scrivere:

if (X mod 2) = 0 then
    begin
        Write('Il numero inserito ');
        WriteLn('è pari');
    end;

In tal caso, le due istruzioni Write e WriteLn saranno eseguite in sequenza.

Ricapitolando:

Definizione

Istruzioni if then

In Object Pascal, un'istruzione condizionale if then permette di eseguire un'istruzione nel caso in cui si verifichi una condizione. In particolare, quando la condizione, che deve essere un'espressione booleana, risulti pari a true. La sintassi dell'istruzione if then è la seguente:

if condizione then
    istruzione;
  • condizione è un'espressione booleana;
  • istruzione può essere un'istruzione semplice o composta, ossia formata da più istruzioni comprese tra begin e end:
if condizione then
    begin
        istruzione_1;
        istruzione_2;
        { ... }
        istruzione_n;
    end;

Istruzione if then else

Il secondo tipo di istruzioni if ci permette di scegliere tra due istruzioni alternative: una per il caso in cui la condizione sia verificata, l'altra in caso contrario.

Ritornando all'esempio di prima, il programma stampa un messaggio nel caso in cui il numero intero introdotto dall'utente sia pari. In caso contrario non fa nulla. Modifichiamo, quindi, il programma in maniera tale da mostrare un messaggio diverso nel caso in cui il numero sia dispari:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
program pari_o_dispari_v2;

var
    X: Integer;
begin
    Write('Inserisci un numero: ');
    ReadLn(X);
    if (X mod 2) = 0 then
        WriteLn('Il numero inserito è pari')
    else
        WriteLn('Il numero inserito è dispari');
end.

In questo caso abbiamo aggiunto la clausola else alla riga 10, che ci permette di specificare cosa fare nel caso in cui la condizione non è soddisfatta.

Nel gergo tecnico, le istruzioni da eseguire nel caso in cui la condizione sia positiva e quelle da eseguire nel caso in cui, invece, sia negativa, prendono il nome, rispettivamente, di ramo then e ramo else.

Un'importante dettaglio da notare riguarda la riga 9: al termine dell'istruzione non abbiamo inserito un punto e virgola ;. Infatti, il compilatore object pascal considera il costrutto if then else come un'unica istruzione complessa. Per cui, il punto e virgola va posto esclusivamente alla fine dopo l'istruzione del ramo else.

Anche nel caso di istruzioni if then else vale il discorso che le istruzioni da eseguire nel ramo then e else possono essere istruzioni complesse, purché racchiuse tra begin e else. Avremmo, infatti, potuto scrivere:

if (X mod 2) = 0 then
    begin
        Write('Il numero inserito è ');
        WriteLn('pari');
    end
else
    begin
        Write('Il numero inserito è ');
        WriteLn('dispari');
    end;

Anche in questo caso bisogna ricordarsi di non inserire il punto e virgola al termine del primo end

Ricapitolando:

Definizione

Istruzioni if then else

In Object Pascal, un'istruzione condizionale if then else permette di scegliere tra due istruzioni da eseguire in base al valore di una condizione booleana. In particolare, quando la condizione booleana risulta pari a true viene eseguita l'istruzione che segue la parola chiave then. Se, invece, la condizione risulta pari a false viene eseguita l'istruzione che segue la parola chiave else. La sintassi dell'istruzione if then else è la seguente:

if condizione then
    istruzione_1
else
    istruzione_2;
  • condizione è un'espressione booleana;
  • istruzione_1 e istruzione_2 prendono il nome di rami dell'istruzione if. In particolare:
    • istruzione_1 prende il nome di ramo then
    • istruzione_2 prende il nome di ramo else
  • istruzione_1 e istruzione_2 possono essere istruzioni semplici o composte, ossia formate da più istruzioni comprese tra begin e end:
if condizione then
    begin
        istruzione_1_1;
        istruzione_1_2;
        { ... }
        istruzione_1_n;
    end
else
    begin
        istruzione_2_1;
        istruzione_2_2;
        { ... }
        istruzione_2_m;
    end;

Istruzioni else if

Le istruzioni if then else permettono di scegliere tra due rami o percorsi di istruzioni differenti in base al fatto che una condizione booleana sia vera o falsa.

Nella stesura di programmi potrebbe sorgere la necessità di poter scegliere tra più di due rami in base al valore di più condizioni. Supponiamo di voler realizzare un programma che, dato un numero intero in ingresso, stampi a schermo un messaggio in base al fatto che il numero sia minore di 100, compreso tra 100 e 200 oppure maggiore di 200. In tal caso, stiamo parlando di tre possibilità. Per poter far questo dobbiamo utilizzare l'istruzione else if, ossia concatenare due istruzioni if then else tra di loro. Per capire come fare, osserviamo l'esempio:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
program test_numero;

var
    X: Integer;
begin
    Write('Inserisci un numero: ');
    Read(X);
    if X < 100 then
        WriteLn('Il numero è minore di 100')
    else if (X >= 100) and (X <= 200) then
        WriteLn('Il numero è compreso tra 100 e 200')
    else
        WriteLn('Il numero è maggiore di 200');
end.

In questo programma abbiamo ben tre rami di esecuzione diversi in base al valore della variabile X. In particolare, nella riga 10 abbiamo concatenato un'altra istruzione if alla precedente. La concatenazione non ha limiti e possiamo aggiungere quante clausole if then vogliamo. In questo modo, tuttavia, il codice può risultare complesso, per cui a volte conviene utilizzare le istruzioni case che vedremo nella prossima lezione.

Riassumendo:

Definizione

Concatenazione di istruzioni if then else

In Object Pascal, è possibile concatenare più istruzioni if then else. Questo risulta necessario nei casi in cui non vi sia un'unica condizione booleana, che può essere vera o falsa, ma più condizioni complesse. In tal caso la sintassi da utilizzare è:

if condizione_1 then
    istruzione_1
else if condizione_2 then
    istruzione_2
else if condizione_3 then
    istruzione_3
{ ... }
else
    istruzione_finale;
  • condizione_i sono espressioni booleane;
  • istruzione_i possono essere istruzioni semplici o composte, ossia formate da più istruzioni comprese tra begin e end
  • le istruzioni istruzione_i prendono il nome di rami.

Quando si usano istruzioni if then else concatenate bisogna prestare attenzione all'ordine di valutazione. Prendiamo l'esempio che segue:

if condizione_1 then
    istruzione_1
else if condizione_2 then
    istruzione_2
else if condizione_3 then
    istruzione_3
else
    istruzione_4;

In questo caso, se la condizione condizione_1 risulta essere pari a true allora verrà eseguita l'istruzione istruzione_1. In caso contrario viene valutata la condizione condizione_2. Nel caso in cui sia pari a true viene eseguita l'istruzione istruzione_2. E così via.

Definizione

Ordine di valutazione nelle istruzioni if then else concatenate

In Object Pascal, quando più istruzioni if then else sono concatenate tra di loro, le condizioni vengono valutate in sequenza. Pertanto, verrà eseguita l'istruzione del ramo then corrispondente alla prima condizione pari a true. Nel caso in cui nessuna condizione risulti vera, verrà, infine, eseguita l'istruzione corrispondente al ramo else finale, se presente.

Prendendo la sintassi seguente:

if condizione_1 then
    istruzione_1
else if condizione_2 then
    istruzione_2
else if condizione_3 then
    istruzione_3
{ ... }
else
    istruzione_finale;

Le condizioni verranno valutate in ordine.

  1. Verrà valutata la condizione condizione_1.
  2. Se la condizione condizione_1 risulta vera verrà eseguita l'istruzione istruzione_1
  3. In caso contrario verrà valutata la condizione condizione_2
  4. Se la condizione condizione_2 risulta vera verrà eseguita l'istruzione istruzione_2
  5. Si procede in ordine fino alla condizione condizione_n
  6. Se l'ultima condizione condizione_n risulta falsa viene eseguita l'istruzione istruzione_finale

Per questo motivo bisogna fare attenzione ad usare le istruzioni if then else concatenate. Prendiamo un esempio: supponiamo di volere scrivere un programma che prende in ingresso due numeri interi A e B. In base al valore di questi due numeri il programma deve stampare un diverso messaggio a schermo:

  • Se A è maggiore o uguale a zero e B è maggiore o uguale a zero deve stampare il messaggio COND1;
  • Se B è minore di zero deve stampare il messaggio COND2;
  • Se A è minore di zero deve scrivere il messaggio COND3.

In base a queste specifiche potremmo essere tentati di scrivere il programma in questo modo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
program test_a_b_sbagliato;

var
    A: Integer;
    B: Integer;
begin
    Write('Inserisci A: ');
    Read(A);
    Write('Inserisci B: ');
    Read(B);
    if (A >= 0) and (B >= 0) then
        WriteLn('COND1')
    else if (B < 0) then
        WriteLn('COND2')
    else if (A < 0) then
        WriteLn('COND3');
end.

Il problema di questo programma sta nel fatto di aver usato delle istruzioni if then else concatenate. Infatti, supponiamo di dare in input al programma i valori:

  • A = -1
  • B = -1

Quindi entrambe negativi. Arrivati alla riga 11 il programma andrà dapprima a verificare la condizione:

(A >= 0) and (B >= 0)

che risulta negativa. Per cui, il programma andrà alla riga 13 e valuterà la condizione:

(B < 0)

che risulta positiva. Quindi verrà stampato a schermo il messaggio COND2. A questo punto, però, il programma uscirà dalla catena di if then else. La condizione

(A < 0)

che è vera, non verrà valutata, per cui il messaggio COND3 non verrà stampato a schermo. Il modo corretto di scrivere il programma è il seguente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
program test_a_b_corretto;

var
    A: Integer;
    B: Integer;
begin
    Write('Inserisci A: ');
    Read(A);
    Write('Inserisci B: ');
    Read(B);
    if (A >= 0) and (B >= 0) then
        WriteLn('COND1')
    else
        begin
            if (B < 0) then
                WriteLn('COND2');
            if (A < 0) then
                WriteLn('COND3');
        end;
end.

Quindi, piuttosto che concatenare le istruzioni if then else, bisogna mettere due istruzioni if separate in un blocco begin end nel ramo else. Questa versione del programma, se diamo in input due numeri negativi, si comporta correttamente stampando a schermo due messaggi:

COND2
COND3

In questo caso, quello che abbiamo fatto nel secondo programma è stato di innestare un'istruzione if all'interno di un'altra.

Istruzioni if innestate

Nell'ultimo esempio abbiamo visto che è possibile innestare delle istruzioni if all'interno di altre:

Definizione

Innestare le istruzioni if

In Object Pascal, è possibile innestare delle istruzioni if all'interno di altre istruzioni if. Per farlo basta semplicemente sostituire al posto di una delle istruzioni relative al ramo then o else l'istruzione if desiderata:

if condizione then
    if condizione_innestata then
        istruzione_1
    else
        istruzione_2
else
    if condizione_innestata_2 then
        istruzione_3
    else
        istruzione_4;

Le istruzioni if interne possono, a loro volta, ospitare altre istruzioni if innestate.

Nell'innestare le istruzioni if bisogna, però, prestare molta attenzione. Esiste, infatti, il cosiddetto problema dell'else appeso (dall'inglese Dangling else problem).

Per capire cosa sia, partiamo da un esempio:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
if X >= 0 then
    if Y >= 0 then
        WriteLn('X e Y Positivi')
    else
        WriteLn('X Positivo - Y Negativo')
else
    if Y >= 0 then
        WriteLn('X Negativo e Y Positivo')
    else
        WriteLn('X e Y Negativi');

In questo esempio, abbiamo delle funzioni if innestate che scrivono un messaggio diverso a seconda del fatto che le variabili X e Y siano positive o meno. Esistono, infatti, quattro combinazioni possibili coperte dai vari rami delle istruzioni if.

A questo punto, se rimuoviamo le righe 4 e 5 otteniamo il seguente stralcio di codice:

1
2
3
4
5
6
7
8
if X >= 0 then
    if Y >= 0 then
        WriteLn('X e Y Positivi')
else
    if Y >= 0 then
        WriteLn('X Negativo e Y Positivo')
    else
        WriteLn('X e Y Negativi');

A prima vista può sembrare banale, ma questo pezzo di codice nasconde un'insidia: l'else di riga 4 a quale if si riferisce?

Si potrebbe pensare che quell'else si riferisca all'if della riga 1 ma ciò è sbagliato! Infatti, l'Object Pascal, in casi ambigui come questo, associa l'else all'istruzione if più vicina, che in questo caso risulta essere quella di riga 2.

L'indentazione in questo caso ci ha tirato un brutto scherzo. Dal punto di vista del compilatore, l'indentazione del codice è ininfluente. Sarebbe stato più corretto scrivere in questo modo:

1
2
3
4
5
6
7
8
if X >= 0 then
    if Y >= 0 then
        WriteLn('X e Y Positivi')
    else
        if Y >= 0 then
            WriteLn('X Negativo e Y Positivo')
        else
            WriteLn('X e Y Negativi');

Per cui, rimuovendo quelle righe di codice, il programma si comporterà in maniera diversa da quanto ci saremmo aspettati.

Come si può risolvere questo problema? Semplicemente racchiudendo il ramo di codice tra begin e end, nel modo che segue:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
if X >= 0 then
    begin
        if Y >= 0 then
            WriteLn('X e Y Positivi')
    end
else
    if Y >= 0 then
        WriteLn('X Negativo e Y Positivo')
    else
        WriteLn('X e Y Negativi');

Solo in questo modo il compilatore potrà capire che l'else fa riferimento al primo if di riga 1.

Riassumendo:

Definizione

Problema del Dangling else

In Object Pascal, in presenza di istruzioni if then else innestate, se non vengono esplicitamente racchiuse le istruzioni tra begin e end, si usa la convenzione di associare un else al più vicino if di cui ne è sprovvisto.

In questo caso, la clausola else è associata al secondo if:

if condizione_1 then
    if condizione_2 then
        istruzione_1
    else
        istruzione_2;

In quest'altro caso, usando esplicitamente begin e end, la clausola else è associata al primo if:

if condizione_1 then
    begin
        if condizione_2 then
            istruzione_1
    end
else
    istruzione_2;

In entrambe i casi, l'indentazione del codice è ininfluente.

Riassumendo

In questa lezione abbiamo visto la sintassi delle istruzioni condizionali if. Abbiamo visto come specificare la condizione booleana da verificare e come specificare le istruzioni da eseguire nel caso in cui la condizione sia soddisfatta e viceversa attraverso la tripletta if then else.

Per condizioni più complesse, che non si limitino al caso true o false abbiamo visto come concatenare più istruzioni if tra di loro. Inoltre, abbiamo visto anche come innestare più if, l'una dentro l'altra, scoprendo, anche, che in tal caso vi sono delle insidie: il problema del Dangling else.

Esiste, tuttavia, un altro tipo di istruzioni condizionali che possono essere usate quando le condizioni da gestire diventano troppo complesse: le istruzioni case che vedremo nella prossima lezione.