Istruzioni di Assegnamento in Object Pascal

Concetti Chiave
  • Un'istruzione di assegnamento in Object Pascal ha la forma NomeVariabile := Espressione;.
  • L'l-value (left value) è l'espressione a sinistra dell'operatore di assegnamento e deve essere qualcosa che può essere modificato, come una variabile.
  • L'r-value (right value) è l'espressione a destra dell'operatore di assegnamento e può essere qualsiasi espressione che produce un valore.
  • Il tipo di dato dell'l-value deve essere identico o convertibile al tipo di dato dell'r-value per rendere valida l'istruzione di assegnamento.
  • Inizializzare una variabile significa assegnarle un valore iniziale prima di utilizzarla.
  • Le variabili globali in Object Pascal sono inizializzate automaticamente ai loro valori predefiniti (zero per numeri, stringa vuota per stringhe, nil per tipi di dato riferimento).
  • Le variabili locali non inizializzate contengono valori casuali o indefiniti, il che può portare a comportamenti imprevedibili nel programma.

Istruzioni di Assegnamento

Un'istruzione di assegnamento permette di assegnare il valore di un'espressione a una variabile. In altre parole, viene modificato il contenuto di una variabile con il risultato di un'espressione.

La sintassi generale di un'istruzione di assegnamento è la seguente:

NomeVariabile := Espressione;

Una cosa che spiazza i programmatori abituati ad altri linguaggi è il fatto che in Object Pascal l'operatore di assegnamento ha una forma particolare, essendo costituito, cioè, da due punti seguito da un uguale: :=. Il singolo uguale (=), che viene utilizzato per le assegnazioni in molti altri linguaggi, in Object Pascal viene utilizzato per testare l'uguaglianza.

Linguaggi come C e derivati, nonché il Python, usano il simbolo = per l'assegnazione e == per il test di uguaglianza.

L'utilizzo di simboli diversi per l'assegnazione e il test di uguaglianza è un sotto prodotto di come sono realizzati i compilatori. In questo modo la compilazione di un'istruzione di assegnamento non può essere confusa con un'istruzione di test di uguaglianza e il processo di traduzione risulta più semplice e veloce.

Dettagli sull'Assegnamento

In gergo tecnico, gli elementi di un'istruzione di assegnamento prendono i nomi di l-value e r-value:

  • l-value (left value o valore sinistro): è il nome dell'espressione a sinistra dell'operatore di assegnamento.
  • r-value (right value o valore destro): è l'espressione a destra dell'operatore di assegnamento, il cui valore viene calcolato ed assegnato alla variabile a sinistra.

La differenza principale tra i due è che l'l-value deve essere necessariamente qualcosa che ha un indirizzo di memoria, come una variabile, e che pertanto può essere modificato. L'r-value, invece, può essere qualsiasi espressione che produce un valore, come una costante, una variabile, o un'espressione più complessa. Motivo per cui, un l-value è anche un valido r-value, ma non il contrario.

Chiariamo con qualche esempio:

var
    a: Integer;
    b: Integer;
begin
    a := 10;          // Assegna il valore 10 alla variabile a
    b := a + 5;      // Assegna alla variabile b il valore di a più 5
    a := b * 2;      // Assegna alla variabile a il valore di b moltiplicato per 2

    // ERRORE!
    10 := a;         // Non valido: 10 non è un l-value
    (a + b) := 20;   // Non valido: (a + b) non è un l-value
end;

In questo frammento di codice abbiamo cinque assegnamenti di cui due non sono validi:

  1. a := 10;

    Questo assegnamento è valido perché a è una variabile (un l-value) e 10 è una costante letterale;

  2. b := a + 5;

    Anche questo assegnamento è valido perché b è una variabile (un l-value) e a + 5 è un'espressione che produce un valore (un r-value);

  3. a := b * 2;

    Anche questo assegnamento è valido perché a è una variabile (un l-value) e b * 2 è un'espressione che produce un valore (un r-value);

  4. 10 := a;

    Questo assegnamento non è valido perché 10 è una costante letterale e non può essere modificata. Pertanto, non è un l-value;

  5. (a + b) := 20;

    Questo assegnamento non è valido perché a + b è un'espressione che produce un valore, ma non è una variabile e pertanto non può essere modificata. Quindi, non è un l-value.

In sintesi:

Definizione

Prima regola di validità di un'istruzione di assegnamento

Un'istruzione di assegnamento è valida se e solo se l'l-value è una variabile o un altro elemento che può essere modificato (come un elemento di un array o un campo di un record).

L'altra regola riguarda i tipi di dato delle espressioni coinvolte nell'assegnamento:

  1. Il tipo di dato dell'l-value deve essere identico al tipo di dato dell'r-value; oppure
  2. Il tipo di dato dell'r-value deve essere convertibile al tipo di dato dell'l-value.

Studieremo nel dettaglio i tipi di dato in una lezione successiva; per ora analizziamo le due regole con qualche esempio:

var
    a: Integer;
    b: Real;
    c: String;
begin

    a := 10;          // Valido: Integer := Integer
    b := 3.14;       // Valido: Real := Real
    c := 'Hello';    // Valido: String := String

    a := b;          // Valido: Integer := Real (Real è convertibile in Integer)
    b := a;          // Valido: Real := Integer (Integer è convertibile in Real)

    a := 'Hello';    // ERRORE! Non valido: Integer := String
    c := 10;        // ERRORE! Non valido: String := Integer
end;

In questo esempio abbiamo otto assegnamenti:

  • I primi tre sono validi perché i tipi di dato dell'l-value e dell'r-value sono identici;
  • I successivi due sono validi perché i tipi di dato dell'r-value sono convertibili in quelli dell'l-value; studieremo le conversioni di tipo in una lezione successiva;
  • Gli ultimi due non sono validi perché i tipi di dato dell'r-value non sono né identici né convertibili in quelli dell'l-value.

In sintesi:

Definizione

Seconda regola di validità di un'istruzione di assegnamento

Un'istruzione di assegnamento è valida se e solo se il tipo di dato dell'l-value è identico o convertibile al tipo di dato dell'r-value.

Inizializzazione delle Variabili

Un concetto fondamentale legato alle istruzioni di assegnamento è quello di inizializzazione delle variabili.

Inizializzare una variabile significa assegnarle un valore iniziale prima di utilizzarla. In molti linguaggi di programmazione, le variabili non inizializzate contengono valori casuali o indefiniti, il che può portare a comportamenti imprevedibili nel programma.

Object Pascal, invece, inizializza automaticamente le variabili globali a dei valori predefiniti (come zero per i numeri, stringa vuota per le stringhe, e nil per i tipi di dato riferimento).

Ad esempio:

program EsempioInizializzazione;

var
    a: Integer;  // Inizializzato a 0
    b: Real;     // Inizializzato a 0.0
    c: String;   // Inizializzato a ''
begin
    WriteLn(a); // Stampa 0
    WriteLn(b); // Stampa 0.0
    WriteLn(c); // Stampa una stringa vuota
end;

Se proviamo a compilare ed eseguire questo programma notiamo due cose:

  1. Il compilatore genera degli avvisi che indicano che le variabili a, b e c non sono state inizializzate. Questo perché, anche se Object Pascal le inizializza automaticamente, è buona pratica inizializzare esplicitamente le variabili per evitare confusione e migliorare la leggibilità del codice.
  2. Quando eseguiamo il programma, vediamo che le variabili contengono i valori predefiniti attesi:

    0
    0.0
    

Non sempre, però, vogliamo che le variabili siano inizializzate ai valori predefiniti. A volte, infatti, vogliamo assegnare loro un valore specifico all'inizio del programma.

La tecnica per inizializzare le variabili dipende dal loro ambito, globale o locale. Vediamo come fare in entrambi i casi.

Inizializzazione delle Variabili Globali

Per le variabili globali, è possibile assegnare un valore iniziale mentre si dichiara la variabile nella sezione var del programma o dell'unità.

La sintassi è la seguente:

var
    NomeVariabile: TipoDato = ValoreIniziale;
    { ... altre variabili ... }
begin
    { ... codice del programma ... }
end;

Ad esempio, per inizializzare due variabili globali a e b possiamo scrivere:

var
    a: Integer = 10;
    b: Boolean = True;

Questa tecnica di inizializzazione funziona solo per le variabili globali.

Inizializzazione delle Variabili Locali

Le variabili dichiarate all'inizio di una procedura o funzione, invece, non vengono inizializzate a un valore predefinito e non hanno una sintassi di assegnazione.

Per queste variabili, bisogna esplicitamente assegnare un valore prima di utilizzarle all'interno del corpo della procedura o funzione. Studieremo le procedure e le funzioni nelle prossime lezioni, ma per ora vediamo un esempio di come inizializzare una variabile locale:

procedure EsempioInizializzazioneLocale;
var
    a: Integer;  // Variabile locale non inizializzata
begin
    a := 10;     // Inizializzazione esplicita
    WriteLn(a);  // Stampa 10
end;

Un'altra differenza importante tra variabili globali e locali riguarda il loro stato quando non vengono inizializzate esplicitamente. Infatti, se non si inizializza una variabile locale ma la si utilizza così com'è, la variabile avrà un valore totalmente casuale (a seconda dei byte che erano presenti in quella posizione di memoria).

In diversi scenari, il compilatore avviserà del potenziale errore, ma non sempre.

Ad esempio:

procedure EsempioVariabileNonInizializzata;
var
    a: Integer;  // Variabile locale non inizializzata
begin
    WriteLn(a);  // Valore casuale
end;

Il compilatore avviserà che a non è inizializzata, e, quando si esegue il programma, si troverà che l'output sarà un valore totalmente casuale che visualizza qualsiasi byte che si trovava nella posizione di memoria della variabile a interpretato come un Integer.