Programmazione orientata agli oggetti in ANSI-C. Progetto

Lasciateci trarre qualche conclusione dall'esperimento nel preprocessing di Point. Abbiamo iniziato con una descrizione line-oriented molto ma molto semplice che possiamo riassumerer così come segue:

interface lines // arbitrary
%prot
representation lines
% metaclass[: metasuper] class: super { // header
... // object components
% // statically linked
type name ([const] _self, ...);
...
%- // dynamically linked
type name ([const] _self, ...);
...
%}

La sola difficoltà consiste nel fatto che vi è la necessità di gestire correttamente la lista dei parametri e suddividere le informazioni di tipo e di nome per ogni dichiarazione. Una soluzione banale sarebbe quella di richiedere che const precede il tipo e che il tipo preceda completamente il nome. Possiamo individuare inoltre i seguenti casi speciali:

_self message target in the current class
_name other object in the current class
class @ name object in other class

Tutti questi possono essere preceduti da const. Gli oggetti nella classe corrente vengono dereferenziati al momento dell'importazione.

Il nome del file per una descrizione di classe è il nome della classe seguito da .d così da permettere a ooc di localizzare le descrizioni delle superclassi. Non dobbiamo preoccuparci poi molto circa la metaclasse: sia che la classe abbia la stessa metaclasse della sua superclasse, sia che una classe abbia una nuova metaclasse e la superclasse di questa metaclasse sia la metaclasse della superclasse della classe. Se leggiamo quindi la descrizione della superclasse, avremo sufficineti informazioni per determinare la metaclasse.

Una volta che ooc abbia analizzato la descrizione di classe, disporrà di sufficienti informazioni per generare i file di interfaccia e di rappresentazione. E' saggio progettare i comandi che funzionino come filtri, ossia che siano in grado di richiedere esplicitamente o tramite redirezione di creare un file, ecco che quindi arriviamo alla classica metodologia di invocazione dei preprocessori.

$ ooc Point —h > Point.h # interface file
$ ooc Point —r > Point.r # representation file

Il file di implementazione è molto più difficile da realizzare. In qualche modo ooc deve trovare i corpi dei metodi e verificare o meno quali parametri sono da controllare o da importare. Se aggiungiamo i corpo dei metodi al file che contiene la descrizione di classe, metteremmo assieme due aspetti diversi, il chè ci causerebbe ulteriore difficoltà nella fase di processing: durante ogni chiamata ad ooc, ooc dovrà caricare i file della descrizione di classe, tutti fino ad arrivare alla classe radice. Tuttavia, i corpi dei metodi sono interessanti praticamente solo per quanto riguarda il file di descrizione più esterno nella gerarchia delle classi. Inoltre, le implementazioni possono cambiare più facilmente rispetto alle interfacce. Se i corpi dei metodi sono mantenuti nella descrizione delle classi, il comando make creerà i file interfaccia ogni volta che verrà modificato il corpo di un qualsiasi metodo e questo probabilmente porterà a dover effettuare un numero nutrito di ricompilazioni che sono tutt'altro che utili o esenti da errore.

La soluzione meno complessa e quindi meno costosa sarebbe quella di permettere a ooc di leggere una descrizione di classe e di produrre uno skeleton per il file di implementazione contenente tutti i possibili header dei metodi per una classe, assieme ai nuovi selettori, se ve ne sono, e con il codice di inizializzazione. Ciò richiede un ciclo dalla classe corrente fino alle sue superclassi per generare gli headers e il corpo dei metodi, tutti questo per tutti i metodi linkati dinamicamente che abbiamo incontrato lungo la via. Ooc sarebbe invocato così:

$ ooc Point —dc > skeleton # starting an implementation

Ciò provvede a fornire un punto di partenza molto comodo per procedere con una nuova implementazione. In generale, però, è una soluzione che è difficile da mantenere in efficienza. Lo skeleton conterrà infatti tutti i metodi possibili. L'idea base è eliminare quelli di cui non c'è la necessità. Comunque, è comunque vero che ogni metodo apparirà due volte: una con un header e con un corpo “fake” e una volta con la lista di argomenti nella descrizione di classe. E' difficile ma assolutamente essenziale mantenere la perfetta coerenza delle descrizioni

ooc è pensato per essere un tool per semplificare lo sviluppo e la manutenzione del codice. Se cambiamo l'header del metodo nella descrizione di classe è ragionevole aspettarsi che ooc propaghi il cambiamento in tutti i file di implementazione. Con l'approccio skeleton possiamo però produrre un nuovo skeleton e manualmente effettuare l'editing di correzione dove serve: non siamo però di fronte ad una piacevole prospettiva!

Se non vogliamo memorizzare i corpi dei metodi all'interno di una descrizione di classe e se richiediamo che ooc vada a cambiare un file di implementazione già esistente se necessario, dobbiamo fare in modo di far funzionare ooc come preprocessore.

ooc carica la descrizione di classe di Point e poi legge il file di implementazione Point.dc e scrive una versione preprocessata di questo file su standard output. Possiamo anche combiare questo con l'approccio skeleton descritto al di sopra.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend