Logo

Marco Cantù
Essential Pascal


Tradotto dall'inglese da: Paolo Rossi

Capitolo 11
Programmi e unit

Le applicazioni Delphi fanno un intensivo uso delle unit, o moduli di programma. Le unit, di fatto, sono le basi della modularizzazione nel linguaggio prima che le classi fossero introdotte. In un'applicazione Delphi, ogni form ha una corrispondente unit dietro ad esso. Quando si aggiunge un nuovo form ad un progetto (con la toolbar corrispondente o dal menu File -> New Form) Delphi in realta' aggiunge una nuova unit, che definsce la classe del nuovo form.

Unit

Se e vero che ogni form e' definito in una unit, non e' invece vero il contrario. Le unit non devono necessariamente definire un form, esse possono semplicemente definire e rendere disponibili una raccolta di routine. Selezionando il comando di menu File -> New e l'icona "Unit" nell'Object Repository, si aggiunge una unit vuota nel progetto corrente. Questa unit contiene il seguente codice, che delimita le sezioni in cui e' divisa una unit:

unit Unit1;

interface

implementation

end.

Il concetto di una unit e' semplice. Una unit ha un nome univoco che corrisponde al nome del file, una sezione d'interfaccia che dichiara cosa e' visibile alle altre unit e una sezione d'implementazione con il codice reale e altre dichiarazioni nascoste. Infine, la unit puo' avere una sezione di inizializzazione (opzionale) con codice che viene eseguito quando il programma e' caricato in memoria e una sezione di finalizzazione (opzionale) con codice che viene eseguito quando il programma viene terminato.

La struttura generale di una unit, con tutte le possibili sezioni e' la seguente:

unit unitName;

interface

// other units we need to refer to
uses
  A, B, C;

// exported type definition
type
  newType = TypeDefinition;

// exported constants
const
  Zero = 0;

// global variables
var
  Total: Integer;

// list of exported functions and procedures
procedure MyProc;

implementation

uses
  D, E;

// hidden global variable
var
  PartialTotal: Integer;

// all the exported functions must be coded
procedure MyProc;
begin
  // ... code of procedure MyProc
end;

initialization
  // optional initialization part

finalization
  // optional clean-up code

end.

La clausola uses all'inizio della sezione d'interfaccia indica a quali altre unit si vuole accedere dalla sezione d'interfaccia. Queste includono le unit che definiscono i tipi di dati di cui abbiamo bisogno nella definizione di altri dati, come i componenti usati nel form che si sta definendo.

La seconda clausola uses, all'inizio della sezione d'implementazione, indica ulteriori unit che servono solo nel codice di implementazione. Quando bisogna riferirsi ad altre unit nel codice delle routine e metodi, si possono aggiungere le unit in questa seconda clausola uses invece che nella prima. Tutte le unit alla quale ci si riferisce devono essere presenti nella directory di progetto o in una directory del "search path" (si puo' modificare il search path per un progetto nella pagina Directories/Conditionals della finestra di dialogo Project Options).

I programmatori C++ devono sapere che la clausola uses non corrisponde alla direttiva include. L'effetto di un'istruzione uses e' di importare solo l'interfaccia, precompilata, delle unit elencate. La porzione d'implementazione e' considerata solo quando questa unit e' compilata. Le unit alla quale ci si riferisce possono essere sia in codice sorgente (PAS) che nel formato compilato (DCU), ma il compilatore che ha generato le unit deve essere della stessa versione.

L'interfaccia di una unit puo' dichiarare numerosi elementi differenti, incluso procedure, funzioni, varabili globali e tipi. Nelle applicazioni Delphi, i tipi di dato sono probabilmente i piu' usati. Delphi automaticamente crea una nuova classe in una unit ogni volta che si crea un form. Comunque, la dichiarazione di un form non e' certamente la sola funzione delle unit in Delphi. Si possono avere ancora le unit tradizionali, con funzioni e procedure e si possono avere unit con classi che non hanno a che fare con i form o gli elementi visuali.

Unit e Visibilita'

In Pascal, le unit sono la chiave dell'incapsulazione e della visibilita e sono probabilmente anche piu' importanti delle keyword delle classi, private e public. (Di fatto, come si vedra' nel prossimo capitolo, l'effetto della keyword private e' collegato alla visibilita' della unit contenente la classe). La visibilita' di un identificatore (come una variabile, rpocedura, funzione o tipo di dato) e' la porzione di codice nel quale l'identificatore e' accessibile. La regola di base e' che un identificatore e' significativo solo dentro al blocco in cui e' dichiarato. Non si puo' usare un identificatore fuori dal suo blocco di visibilita'. Ecco alcuni esempi.

Qualsiasi dichiarazione nella sezione d'interfaccia di una unit e' accessibile da ogni punto delprogramma che include la unit nella clausola uses. Le variabili della classe form sono dichiarate nello stesso modo, cosi' ci si puo' riferire ad un form (e ai suoi campi, proprieta' e componenti) dal codice di ogni altro form. Ovviamente, non e' buona prassi dichiarare tutto come globale. A parte gli ovvi problemi di consumo di memoria, usare variabili globali rende il programma piu' difficile da mantenere e aggiornare. In breve, si deve usare il minor numero possibile di variabili globali.

Unit come Namespace

L'istruzione uses e' la tecnica standard per accedere ad un'altra unit. A questo punto si ha accesso alle definizioni della unit. Puo' succedere che due unit alla quale ci si riferisce, dichiarino lo stesso identificatore, ovvero due classi o due routine con lo stesso nome.

In questo caso, si puo' semplicemente usare il nome della unit come prefisso al nome della routine definita nella unit. Ad esempio, ci si puo' riferire alla procedura ComputeTotal definita in una unit Totals come Totals.ComputeTotal. Questo non deve accadere spesso, visto che e' una cattiva regola usare nomi uguali per differenti elementi in un programma.

Tuttavia, si si guarda nella libreria VCL e nella API di Windows, si trovera' che alcune funzioni Delphi hanno lo stesso nome (ma in genere diversi parametri) di alcune funzioni Windows disponibili in Delphi stesso. Un esempio e' la procedura Beep.

Se si crea un nuovo programma in Delphi, si aggiunge un pulsante e si scrive il seguente codice:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Beep;
end;

allora, appena si preme il pulsante si sentira' un breve suono. Se si guarda il codice nella clausola uses:

uses
  Windows, Messages, SysUtils, Classes, ...

e si cambia con il seguente (semplicemente spostando la unit SysUtils prima della unit Windows):

uses
  SysUtils, Windows, Messages, Classes, ...

Adesso se si prova a ricompilare questo codice si avra' un errore: "Not enough actual parameters." Il problema e' che la unit Windows definisce un'altra funzione Beep con due parametri. Quello che succede e' che le definizioni della prima unit (nella clausola uses) possono essere nascoste dalle corrispondenti definizioni delle unit successive. La soluzione e' abbastanza semplice:

procedure TForm1.Button1Click(Sender: TObject);
begin
  SysUtils.Beep;
end;

Questo codice compilera' a dispetto dell'ordine delle unit nella clausola uses. Ci sono poche altri conflitti di nome in Delphi, semplicemente perche' il codice Delphi e' contenuto dai metodi delle classi. Avere due metodi con lo stesso nome in due differenti classi non crea alcun problema. Il problema esiste solo con le routine globali.

Unit e Programmi

Un'applicazione Delphi consiste di due tipi di codice sorgente: una o piu' unit e un file di programma. Le unit possono essere considerate files secondari, i quali sono legati alla parte principale dell'applicazione, il programma, In teoria, questo e' vero. In pratica, il file di programma e' normalmente generato automaticamente, ed ha un ruolo secondario. Semplicemente fa partire il programma e visualizza il form principale. Il codice del file di programma, o progetto (DPR), puo' essere editato manualmente o manipolato tramite il Project Manager o i settaggi del Project Options relativi al programma o ai form dell'applicazione.

la struttura del file di programma e' normalmente piu' semplice della struttura delle unit. Ecco il codice sorgente di un file di programma di esempio:

program Project1;

uses
  Forms,
  Unit1 in ‘Unit1.PAS’ {Form1DateForm};

begin
  Application.Initialize;
  Application.CreateForm (TForm1, Form1);
  Application.Run;
end.

Come si puo' vedere, c'e' solo una clausola uses e il codice principale dell'applicazione, racchiuso dalle keyword begin end. La clausola uses del programma e' particolarmente importante, siccome e' usata per gestire la compilazione e il link dell'applicazione.

Conclusioni

At least for the moment, this chapter on the structure of a Pascal application written in Delphi or with one of the latest versions of Turbo Pascal, is the last of the book. Feel free to email me your comment and requests.

Almeno per il momento, questo capitolo sulla struttura di un'applicazione Pascal scritta in Delphi o con una delle ultime versioni del Turbo Pascal, e' l'ultimo del libro. Per commenti e richieste mandare una mail a: Marco

Se dopo questa inroduzione del linguaggio Pascal si vogliono approfondire gli elemnti della programmazione orientata agli oggetti in Object Pascal, ci si puo' indirizzare al mio ultimo libro pubblicato Masterig Delphi 5 (Sybex, 1999). Per maggiori informazioni su questo e altri libri piu' avanzati (anche di altri autori) guardate il mio sito web, www.marcocantu.com/books.

Ritorna all'indice

© Copyright Marco Cantù, Wintech Italia Srl 1995-2000