Newsgroup: it.comp.java
Titolo: TEMPLATE

In Java2 è stato introdotto quello che in C++ è il template ?
Ciao e grazie.

 wrote in message
FNEP4.79955$xt2.9...@news.infostrada.it...


 ha scritto nel messaggio
news:8enb3k$s80$1...@lacerta.tiscalinet.it...


ASTRATTO?)
Si'. Se non hai vincoli, usi Object - la cui ragion d'essere e', tra le altre 
cose, di fornire una nozione di equivalenza semantica ("equals", in 
contrapposizione all'identita' tra riferimenti, ==) e un metodo di hashing 
(hashCode).
Se hai vincoli, puoi esprimerli in termini di un'interfaccia (la quale, spesso 
non si nota, puo' contenere costanti e intere classi, se serve, e non solo 
metodi) oppure, con la tradizionale tecnica intrusiva pre-template, con una 
classe.
Quest'ultima tecnica ha i limiti noti, ma generalmente le prime due funzionano 
molto bene.
Ad esempio, tutti i Containers lavorano su Objects il cui unico requisito e' 
quello, come sopra, di aver definito una nozione ragionevole di equivalenza e 
di hashing, e lavorano molto bene. Certamente con meno efficienza runtime dei 
template alla C++ (non essendo creata una classe al volo a compiletime, c'e' 
qualche overhead intrinseco), ma di norma non e' un gran problema.
E l'uso di interfacce - piuttosto che di classi - per esprimere vincoli 
semantici e' generalmente molto efficace, specialmente unita alle 
caratteristiche di risoluzione e linking dinamico della JVM.
In altre parole, la signature di un metodo non e' sufficiente a garantire che 
il metodo abbia senso.. ma la signature di *molti* metodi da', (almeno 
fenomenologicamente ;-), qualche garanzia in piu'.
-- 
God is Real, unless declared Integer.
ObjectZone - 
http://space.tin.it/computer/csadun

 >dato qualsiasi (cioè la mia classe è a tutti gli effetti un TIPO di DATO


Scusa la poca chiarezza, ma ho un po' di dubbi ...
Questo e' di solito uno dei punti piu' dibattuti tra chi usa  
prevalentemente C++ e chi Java, e meno immediati per chi passa dal primo al 
secondo, quindi sei certamente scusato. ;-)
Alcuni punti preliminari:
- in java, hai un operatore di RTTI (instanceof) gratis, senza 
nemmeno l'overhead di dover #includere nulla o attivare un'opzione del 
compilatore.
- in java, Object a' la radice di ogni gerarchia; inoltre, non e' 
strutturalmente vuoto, ma contiene un'embrionale nozione di equivalenza 
semantica, oltre alla naturale equivalenza per identita' di indirizzamento.
- in java, il linking delle classi e' interamente dinamico, e rende possibile 
la gestione esplicita delle eccezioni dovute a downcast errati, o in 
alternativa garantisce graceful exit senza crash. Inoltre, tali classi sono - 
in caso sia proprio necessario - completamente descrivibili ed attivabili 
(istanziazione, invocazione di metodi, etc) da codice *attraverso* i propri 
descrittori.
Cio' detto, hai subito la tua prima risposta. Quasi sempre, a compile time puoi 
almeno definire l'*insieme* di classi che il tuo container conterra', e usare 
instanceof (o un pattern di stato o di dispatchin) per reagire di conseguenza 
col downcast opportuno. Nel 5% di casi rimanenti, puoi avvalerti delle 
proprieta' di auto-descrizione dello spazio delle classi (in java, 
"reflection") per fare cio' che devi fare. 
Due, quanto sopra (probabilmente non sono stato abbastanza chiaro) *non* e' in 
genere il metodo migliore. Molto spesso, anche se puoi, non *vuoi* fare 
assunzioni sul set di classi di cui sopra - per gli ottimi motivi di s.e. che 
non sto a ripetere. Ma quello che vuoi fare e' definire la *proprieta'* che una 
certa classe deve avere per far parte dell'insieme - in altri termini che 
interfaccia deve presentare. A questo punto, definisci l'interfaccia e,  invece 
che un downcast alla classe, fai un downcast all'interfaccia, e voila' - ti sei 
parato il sedere anche su classi future.
Il punto - che spesso non e' chiaro, e quindi mi permetto di enfatizzare - e' 
che in java *un'interfaccia e' un tipo valido per il sistema*. Al contrario di 
C++ (per l'ottimo motivo che le interfacce non ce le ha :), puoi fare un 
downcast valido ad una sottoclasse e/o ad una qualunque delle interfacce 
implementate.
Tieni presente che la genericita' "alla template" non significa che in un 
container puoi mettere di tutto a runtime (al contrario: in una list<int> ci 
metti solo interi), ma che puoi generare automaticamente contenitori che 
accettano oggetti qualunque, a patto che rispettino certe caratteristiche - 
possiedano metodi con determinate segnature.. in altre parole, implementino una 
particolare interfaccia. :)
Una differenza (e quella per cui io ormai preferisco specificare design in Java  
piuttosto che in C++) e' che in Java sei costretto a identificare 
*esplicitamente* l'interfaccia - e a dichiararne esplicitamente 
l'implementazione - mentre in C++ la cosa e' implicita: il compilatore 
controlla che i metodi necessari ci siano, ma 1. non hai un elemento 
architetturale specifico, facilmente identificabile, con un immediato contenuto 
"conoscitivo", e dotato di nome; 2. siccome il compilatore genera la classe (ed 
effettua la verifica) solo se ne usi un'istanza nel codice, accadono piu' 
facilmente noiosi qui-pro-quo quando l'implementazione completa viene portata 
avanti distintamente dal design; insomma, il compilatore da questo punto di 
vista lavora un po' meno.
Ovunque in C++ avresti usato
template<typename T> class mio_container { ... };
(dove le caratteristiche di T sono dedotte a compiletime, e restano implicite)
in java dici:
interface T { ...caratteristiche esplicite... }
class mio_container { 
    	Vector v; // Container su Object.. Vector, Map, Set, QuelloCheVuoi :)
    	...  // metodi che accettano solo istanze di T
}
richiedendo come contratto della classe che tutti gli oggetti implementino T;
oppure, piu' comunemente, evitando il wrapper "mio_container" sul Vector o 
quelchel'e', e facendo downcast su T 
Vector v;
(T)v.firstElement();
- che e' semanticamente equivalente e ragionevolemnte sicuro viste le 
caratteristiche di loading e linking delle classi.
Ovviamente, tutto cio' si paga in termini di prestazioni. Un template genera 
codice ad hoc per il tipo, che viene poi compilato - un downcast e' comunque un 
overhead.
In conclusione, dal punto di vista architetturale, Java offre la definizione 
esplicita di interfacce, supportata dal compilatore, che manca a C++; dal punto 
di vista prestazionale, e' piu' lento. 


> In Java2 è stato introdotto quello che in C++ è il template ?
Non credo di sapere che cosa sia il template in C++, ma non e`
possibile che sia una Interface in Java o anche solo una abstract
class (da cui non e` possibile creare instances a meno che non si
derivino delle subclass)?
---
Paola Cerioli
http://www.cerioli.com

:

Per la cronaca. :)
Un template e' una specifica di tipo (classe, struttura), parametrizzata da uno 
o piu' tipi generici (o meglio, *denotazioni* di tipo generiche, ma e' un 
dettaglio ;-). Ad esempio, dici pippo<T> e definisci un'operazione "pluto", 
usando a volonta' il tipo generico T, scrivendo per esempio
T pluto(T a, T b) { return a+b; }
Lo usi dichiarando il tipo specifico nel tuo codice, instanziandolo. Ad 
esempio, scrivi "pippo<int> obj;"
*A tempo di compilazione*, quando incontra il "pippo<int>", il compilatore 
verifica che il tipo che fornisci possieda tutti i requisiti necessari; ad 
esempio, nel metodo pluto abbiamo usato un'operazione + tra due elementi di 
tipo T: il compilatore controllera' che per il tipo effettivo (int) 
l'operazione sia definita (o, in termini OO, il tipo int possieda l'operazione 
+) e - se tutto e' a posto - genera al volo una classe (per questo si chiamano 
template) in cui sostituisce il tipo effettivo (int) ovunque appare il tipo 
generico. La tua classe avra' quindi un metodo
int pluto(int a, int b) { return a+b; }
Una volta creata, tale classe e' identica a tutte le altre e viene compilata di 
conseguenza.
Dal punto di vista architetturale, per l'uso "normale" che se ne fa, una 
combinazione interfaccia+classe implementativa+gerarchia a radice unica da' lo 
stesso potere rappresentazionale. 
In realta' con i template si possono fare giochi un po' piu' divertenti (cio' 
che si chiama programmazione generativa), dato che - come sopra - essi vengono 
valutati a *compile time*, e quindi il compilatore si comporta come un mini 
interprete che valuta (a compile time!) espressioni. Questa cosa non e', 
ovviamente, realizzabile con interfacce eccetera.
La cosa ha qualche uso in metodi di ottimizzazione (ad esempio, e' possibile 
"srotolare" cicli a compile time, il che col compilatore medio puo' portare a 
vantaggi in performance) e recentemente ho letto di proposte per un'uso di 
questa potenzialita' in termini di software engineering. Non e' che 'sta cosa 
sia cruciale, pero', anzi. :)
