7. Aspetti avanzati

7.1 Copia e uguaglianza

La semantica di default per le operazioni di assegnamento e di confronto per = fra oggetti prevede che vengano coinvolte solo le identità degli oggetti (in pratica, spesso, dei puntatori di memoria). Nel caso dell'assegnamento questo pu creare degli spiacevoli effetti collaterali  dovuti alla condivisione di strutture dinamiche che si viene a creare. Per evitarli occorre effettuare l'assegnamento con operazioni del tipo a:=copia(b) che ha l'effetto di creare in a  un puntatore ad una copia dell'oggetto indicato in b.
Nel confronto
x = y tra oggetti, se si vuole che il confronto non venga fatto sulle identità (questo quasi sempre il caso) ma bens sullo stato dei due oggetti,  necessario usare operatori diversi come, ad es.,  uguale(x,y) .
In genere i linguaggi mettono a disposizione del programmatore  la possibilità di ridefinire
copia e uguale   classe per classe.

7.2 Asserzioni

Le asserzioni in un linguaggio di programmazione sono delle espressioni booleane valutabili a tempo di esecuzione che  possono assolvere a diversi scopi:

· forma primitiva di specifica e di documentazione

· prevenzione contro possibili malfunzionamenti del software; in particolare nella OOP come precondizioni e postcondizioni dei metodi

· strumento di verifica durante la fase di testing

· possibili clausole di uno stile di programmazione noto come progetto per contratto[Meyer97]

I linguaggi OOP si differenziano notevolmente rispetto al supporto e alla varietà di tipi di asserzioni che mettono a disposizione del programmatore.

7.3 Eccezioni

Per aumentare la robustezza di un'applicazione, tutti i pi recenti linguaggi OOP mettono a disposizione la possibilità definire, sollevare e trattare eccezioni, ciò eventi causati da malfunzionamenti o imprevisti hardware o software che si possono sempre verificare. In particolare il programmatore di ogni metodo ha la possibilità di catturare un'eccezione, riconoscerla e prendere le necessarie azioni di recupero almeno per mantenere l'oggetto in uno stato interno consistente. Il trattamento standard di default quello di propagare l'eccezione al chiamante, fino eventualmente a raggiungere il metodo avviato per primo, facendolo abortire. 

7.4 Contenitori e iteratori

Una volta definito come classe un contenitore astratto di dati (ad es. una pila, una lista, una tabella, ecc.) si può presentare il problema di attraversare uno di questi contenitori,  ciò di costruire cicli del tipo

portati sul primo elemento
finch non sei giunto all'ultimo e  non hai trovato una condizione di arresto
   elabora l'elemento corrente
   passa all'elemento successivo
finefinch

La soluzione pi generale, flessibile e astratta  a questo problema prevede il ricorso a degli oggetti chiamati iteratori la cui classe di appartenenza viene definita in "simbiosi" a quella dei contenitori che li attraversano. In pratica essi assolvono ad un ruolo molto simile a quello rivestito dagli indici dei "for" per l'attraversamento degli array. La differenza che viene completamente nascosta la rappresentazione dei cursori. Il cursore  l'oggetto   che all'interno di un iteratore "punta" all'elemento del contenitore in corso di attraversamento. Questo permette un domani di cambiare sia la rappresentazione dei contenitori che quella degli iteratori senza cambiare il codice delle applicazioni "clienti".

7.5 Distruttori

Oltre ai costruttori può essere talvolta necessario che il programmatore definisca dei metodi, chiamati spesso distruttori, che assolvono al compito di svolgere delle azioni finali prima che l'oggetto venga completamente distrutto e le sue aree di memoria rese disponibili per operazioni di allocazione di nuovi oggetti.  In particolare, in C++, i distruttori hanno spesso l'onere di recuperare parte della memoria occupata dall'oggetto. Da questo onere sono liberi tutti i linguaggi che prevedono il garbage collector, ciò quel processo della macchina virtuale del linguaggio che assolve appunto al compito di individuare e recuperare le aree occupate da oggetti che si rendono inaccessibili ("garbage", appunto).

7.6 Persistenza

  La persistenza nella OOP la proprietà di un oggetto di sopravvivere al processo che l'ha creato. Un modo per implementare la persistenza tipicamente quello di "salvarlo" su un supporto di memoria persistente, come il disco. I linguaggi OOP adottano varie tecniche per fornire questo tipo di servizio all'utenza. Il pi semplice e primitivo  quello di mettere a disposizione delle primitive di salvataggio e recupero di un oggetti su un file con un certo nome. Il pi sofisticato (ma anche il pi semplice da usarsi) quello di prevedere la possibilitàdi dichiarare come persistenti alcune classi: gli oggetti creati saranno automaticamente resi persistenti .

7.7 Covarianza

Una questione che si può porre nel progetto delle classi :  si pu, al momento di ridefinire un metodo (overriding), cambiare il tipo di un parametro formale ?   in particolare: si può specificare un sottotipo ?
I linguaggi si dividono sostanzialmente in due categorie: quelli che rispondono negativamente (linguaggi non-varianti, come C++ e Java) e quelli che rispondono affermativamente (linguaggi covarianti, come Eiffel). Purtroppo la covarianza del sistema di tipi,  pur venendo incontro a utili esigenze pratiche di flessibilità, espone il linguaggio ad alcuni rischi.

7.8 Concorrenza e reti

Fin dal suo concepimento, nel paradigma ad oggetti stato preso in considerazione l'ipotesi di considerare ogni oggetto come avente un proprio "thread of control". In particolare, Smalltalk vedeva la chiamata di un metodo come la spedizione di un messaggio da parte di un oggetto mittente (sender)   ad uno ricevente (receiver) contenente la richiesta di un particolare servizio il cui termine veniva comunicato al mittente assieme all'eventuale  restituzione di un valore. Con una visione pi moderna, si può considerare la chiamata di un metodo come la richiesta di un servizio ad un oggetto servente in grado di  accettare e ordinare opportunamente le richieste provenienti dai vari oggetti clienti. Alcuni linguaggi ad oggetti mettono a disposizione  strumenti od  estensioni a supporto della concorrenza e/o della distribuzione degli oggetti. Ad esempio Java mette a disposizione la libreria RMI (Remote Method Invocation) per la chiamate di metodi ad oggetti remoti.