MokaByte
Numero 32 - Luglio Agosto 99
|
|||
|
programmazione generica |
||
|
Andrea Giovannini |
|
|
Come molti sanno Java nasce come un C++ semplificato e privato delle caratteristiche considerate più pericolose, come aritmetica dei puntatori, ereditarietà multipla , overloading degli operatori e template. Questa opera di semplificazione ha reso Java un linguaggio molto semplice, facile da imparare e col quale è possibile sviluppare programmi in modo molto più agevole rispetto a C++. Col tempo però ci si è resi conto che la semplicità di Java rende il linguaggio un po' limitato per lo sviluppo professionale. Ovviamente anche i progettisti di Java sono consapevoli dei limiti del linguaggio e nel sito di Sun viene mantenuta la Bug Parade di Java, ovvero la lista dei problemi del linguaggio in cui gli sviluppatori possono "votare" quelli che vorrebbero vedere risolti prima possibile. L'introduzione dei template è una delle modifiche più quotate e ultimamente è stata fatta una proposta da Gilad Bracha, uno dei progettisti di Java, nel contesto del Java Community Process. Come vedremo Bracha è anche parte in causa perchè fa anche parte del team di sviluppo di GJ, un compilatore sperimentale che estende Java con i template. Esamineremo più in dettaglio GJ insieme ad un altra proposta del MIT nel seguito dell'articolo |
Introduzione alla programmazione genericaLa programmazione generica è uno stile di programmazione basato sull'utilizzo di classi in cui il tipo di alcuni attributi è un parametro. Diversi linguaggi supportano questo paradigma anche se con caratteristiche diverse. Uno di questi è C++ che oltre a supportare classi generiche, chiamate template, permette anche di definire funzioni generiche in cui il tipo degli argomenti o del valore di ritorno è un parametro. Le classi template sono particolarmente utili per definire contenitori di tipi arbitrari non noti durante la compilazione mentre le funzioni template permettono di realizzare algoritmi generici in grado di operare su collezioni di oggetti arbitrari. Ad esempio un algoritmo di ordinamento come il quicksort è un ottimo candidato per essere definito come algoritmo generico in quanto può essere applicato indifferentemente ad un insieme di interi o di stringhe. C++ ha contribuito molto alla diffusione della programmazione generica grazie a STL (Standard Template Library), una libreria di classi contenitore e algoritmi generici basata sui template. Fra gli altri linguaggi che supportano la programmazione generica troviamo Ada, Eiffel e i linguaggi funzionali come ML che sono stati fra i primi a supportare i tipi parametrici.Vediamo ora un esempio di funzione generica in C++, la funzione max() per il calcolo del massimo fra due elementi template <class T> T max(const T& a, const T& b){
Programmazione generica e programmazione OO Come abbiamo visto l'utilizzo dei template introduce uno stile di programmazione diverso dalla programmazione a oggetti. In particolare la programmazione generica favorisce il riuso di classi e funzioni template ma non fornisce alcun meccanismo per garantire l'estendibilità del codice. L'utilizzo della programmazione ad oggetti permette invece di sviluppare codice estendibile attraverso l'uso dell'ereditarietà. La programmazione generica implementa il cosiddetto polimorfismo parametrico mentre quella OO è basata sul polimorfismo per inclusione basato sulla ridefinizione dei metodi nelle classi derivate. In [1] è possibile trovare un confronto molto approfondito fra questi due stili di programmazione. In questa sede vogliamo soltanto porre in evidenza che
Generic Java (GJ)GJ (Generic Java) è un linguaggio sviluppato da un gruppo di ricercatori fra i quali anche David Stoutamire e Gilad Bracha, entrambi di JavaSoft. Occorre comunque precisare che Sun e JavaSoft non hanno nulla a che fare con il progetto GJ.Le origini di GJ sono da ricercare in Pizza, un precedente linguaggio sviluppato dallo stesso team che estendeva Java con i template e altre caratteristiche tipiche dei linguaggi funzionali. GJ si limita invece al supporto ai template con una maggiore attenzione alla compatibilità con i programmi esistenti scritti in Java. Un tipo parametrico in GJ viene indicato fra parentesi acute <> come in C++. Consideriamo ad esempio la seguente classe Foo class Foo<T> {
Foo<Integer> integerFoo; Una importante caratteristica del linguaggio, che come abbiamo visto è assente in C++, è la possibilità di vincolare esplicitamente ogni tipo parametrico richiedendo che estenda una particolare classe o implementi una data interfaccia. Consideriamo ad esempio il seguente codice class Item<T implements java.io.Serializable> {
interface Checker<T> {diventa interface Checker {
.... public int check(String item) { .... } public int check(Object item) {
Il compilatore utilizza la tecnica del bridging anche per supportare l'overriding covariante dei metodi sul valore di ritorno. Ad esempio class A {
class Test {
I due statement precedenti son illegali perchè il compilatore non ha alcun modo di verificare il parametro String. Ai precedenti problemi si contrappone un più semplice design di GJ, una maggiore efficienza e una migliore compatibilità con il codice esistente. NextGen è un esempio di linguaggio che estende Java con i template mantenendo l'informazione sui tipi a run time e si può considerare un sovrainsieme di GJ. Per quanto riguarda l'interoperabilità con il codice Java esistente GJ permette di
PolyJPolyJ è un'estensione di Java sviluppata al MIT che supporta classi con tipi parametrici. Il compilatore è implementato in C++ come estensione di GuavaC, un compilatore free per Java diffuso sui sistemi Linux. PolyJ è compatibile all'indietro con il codice Java esistente.La prima caratteristica del linguaggio che colpisce è la sintassi per la dichiarazione dei parametri template che vanno racchiusi fra parentesi quadre []. La scelta è orientata a ottenere una semplificazione per il parsing del codice ma è senz'altro discutibile per quanto riguarda la leggibilità. A differenza di GJ è possibile utilizzare come parametri di tipo anche tipi primitivi e array. I parametri possono essere vincolati con una sintassi particolare, le clausole di where. Consideriamo il seguente esempio class SortedList[T] where T { int compare(T); }{
class Foo[T] where T { T add(T); }{
class SortedList[T] where { .... }
.... L'utilizzo delle clausole di where per definire i vincoli è analogo all'uso delle interfacce. A differenza di queste nelle clausole è possibile definire costruttori e metodi statici. Esse permettono inoltre di avere una maggiore granularità nella definizione dei vincoli senza ricorrere a relazioni di ereditarietà. Se consideriamo il fatto che una classe parametrica deve poter essere compilata separatamente da quella usata come parametro possiamo comprendere come sia importante mantenere il massimo disaccoppiamento. L'utilizzo di interfacce o di esplicite relazioni di ereditarietà potrebbe non essere sempre possibile e a volte anche non auspicabile se il loro numero diventa considerevole. Le clausole di where permettono anche di limitare la generazione di codice per i tipi parametrici. Relativamente agli aspetti di compilazione viene generata una classe Java di riferimento per ogni classe parametrica mentre per ogni istanza si genera una classe wrapper che definisce i metodi con i tipi corretti ed esegue i cast opportuni per richiamare i corrispondenti metodi nella classe di riferimento. ValutazioniDopo aver esaminato i due linguaggi possiamo trarre alcune conclusioni.Il compilatore meglio supportato è sicuramente GJ. E' infatti aggiornato alla versione 1.2 di Java mentre PolyJ ha invece la grossa limitazione di supportare al momento solo Java 1.0. Il fatto che PolyJ sia un progetto sviluppato in un laboratorio di ricerca lo rende principalmente una dimostrazione di concetti interessanti (es. le clausole di where) ma non un linguaggio pensato per un utilizzo in ambienti di produzione. Un altro vantaggio di GJ è dato dal supporto ai metodi template polimorfi. Entrambi i linguaggi permettono di definire dei vincoli sui parametri di un template e PolyJ permette al programmatore una maggiore libertà espressiva. ConclusioniIn questo articolo abbiamo esaminato i vantaggi e i problemi della programmazione generica al fine di comprendere le reali necessità di una sua introduzione in Java. Abbiamo quindi visto le due proposte più interessanti in tal senso, GJ e PolyJ. Possiamo senz'altro concludere con la speranza di leggere al più presto su MokaByte un articolo sui template come nuova caratteristica di Java!!Riferimenti
[2] Il sito di GJ: http://www.cs.bell-labs.com/who/wadler/pizza/gj [3] Il sito di PolyJ: http://www.pmg.lcs.mit.edu/polyj |
|
||
|
||
MokaByte ricerca
nuovi collaboratori
|
||
|