Newsgroup: it.comp.java
Titolo: Direttive di preprocessore

Salve,
provendendo da linguaggi come c/c++ ho preso alcuni vizi nella 
programmazione e volevo sapere se in Java esistono comandi corrispondenti ai 
vai #define #ifdef del c/c++.
Oppure se qualche editor permette qualcosa di similare, eseguendo la 
sotituzione delle definizioni prima di passare il codice al compilatore...
grazie,
Roberto 

 sotituzione delle definizioni prima di passare il codice al compilatore...
No, in Java si usa lasciare fare al compilatore e al JIT compiler tutte 
le ottimizzazioni di basso livello.
L'unica cosa che puoi fare è dichiarare alcuni metodi final, in questo 
caso, se il compilatore vuole, potrebbe decidere di mettere il metodo 
inline.
Al posto di #IFDEF si usano gli if normali che controllano dei boolean 
magari statici. Il sistema di logging di java funziona piu' o meno così.
Al posto del
	#define PI 3.14
Si usa
	static final double PI = 3.14;
-- 
Andrea Francia
http://www.andreafrancia.it/


Come già segnalato da AF non è possibile nel linguaggio standard, per
tanti buoni motivi. Però se vuoi farti del male hai tanti ma tanti
strumenti a disposizione, compresi alcuni pre-processori, se non
addirittura linguaggi interi, da basic a ADA, a Cobol a Vattelapesca:
http://www.is-research.de/info/vmlanguages/
--
www.megadix.it

 Perň se vuoi farti del male 
Siccome sono affezionato al preprocessore C/C++ (utile in moltissimi
casi), puoi dirmi perché "farti del male"?
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 
Secondo me va bene usare (responsabilmente) il preprocessore C o C++ 
perché ci si aspetta che gli sviluppatori C e C++ sappiano come funziona.
Usare una modifica che aggiunge un preprocessore a Java è un problema 
perché queste modifiche non sono standard (neanche de-facto) e sono poco 
conosciute.
Con il preprocessore ci puoi fare tante cose, molte utili e alcune brutte.
Esempi di quelle utili sono:
  1. definire costanti
  2. mettere funzioni inline
  3. gestire l'inclusione multipla degli header
  4. includere selettivamente una parte machine dependent.
  5. attivare o disattivare il debug.
In Java queste necessità o sono già risolte da costrutti specifici (1 e 
3), oppure non è richieste averne un controllo così fine come capita con 
applicazioni C o C++(2), o si fanno con altri sistemi (4 e 5).


   2. mettere funzioni inline
Non č appopriato, né quindi consigliabile, gestire nessuna di queste due
caratteristiche con il preprocessore, sia in C che in C++ (sia le costanti
che i membri inline si dichiarano in altro modo). L'uso principale del
preprocessore č quello di far sě che intere sezioni di codice vengano
compilate o meno, e questo per varie esigenze concrete. Non puoi farlo in
nessun altro modo. Devi usare, in generale, necessariamente un
preprocessore.
Per intenderci, il metodo che tu suggerivi (usare una costante, al posto
di una define) non č la stessa cosa. Forse col "final" il compilatore
diventa un po' piů furbo, ma in generale la tecnica non č equivalente.


 diventa un po' piů furbo, ma in generale la tecnica non č equivalente.
D'accordissimo, infatti avevo scritto : "se il compilatore vuole 
*potrebbe* decidere di metterla inline".


 *potrebbe* decidere di metterla inline".
Ma potrebbe non essere così in molti altri casi, per cui ti trovi codice
di debug che appesantisce, di fatto, il compilato finale.



Voleva solo essere un modo simpatico per dire che molti linguaggi
"vecchi" si possono far girare sulla JVM.
In secondo luogo, per rispondere al tuo dubbio: penso che le macro in
Java siano *abbastanza* una sciocchezza, per alcuni motivi. Provo a
rispondere alle questioni sollevate da Andrea Francia:
1. definire costanti
Non mi sembra sia obbligatorio usare una macro :)
2. mettere funzioni inline
In Java le ottimizzazioni sono appannaggio esclusivo del compilatore,
della JVM e non ultimo del JIT (se c'è). Quando finalmente capisci
come ottimizzare un pezzo di codice, il giorno dopo esce un JIT più
furbo di te. Sperimentato di persona.
3. gestire l'inclusione multipla degli header
Java non usa header :)
4. includere selettivamente una parte machine dependent
Java, a differenza di C/C++, ha la Reflection, che risolve il 99% di
questi problemi. Ad esempio io posso definire l'interfaccia della mia
classe e implementarla in dieci modi diversi, anche nativamente, poi a
runtime istanzio l'implementazione che mi serve. Ripassare il pattern
AbstractFactory ;)
5. attivare o disattivare il debug
Beh, avete mai usato Log4j o simili?
Spero di non averti confuso ulteriormente le idee...
--
www.megadix.it


Nessun problema per come viene solitamente utilizzato Java, ma sono
comunque istruzioni in piu'. Per il logging comunque va bene.

 Java, a differenza di C/C++, ha la Reflection,
C++ supporta RTTI, ma è buona regola non usarlo con disinvoltura. Ahimè,
c'è tanta gente invece che lo fa. Forse ex-javisti abituati alla
reflection :-P :-P :-P


 Provo a rispondere alle questioni sollevate da Andrea Francia
L'idea del mio post era questa: il preprocessore in Java non è così 
utile come in altri linguaggi perché per tutti i problemi 
tradizionalmente risolti dal preprocessore o sono già risolti in altri 
modi o non sono così sentiti come lo sono in altri linguaggi.


modi 
Ma è appunto questo il punto: i modi in cui sono risolti questi
problemi in Java sono altrettanto "powerful" (non mi viene la parola e
"potenti" non mi piace) che in altri linguaggi?. Se mi parli di codice
di debug scritto con istruzioni esplicite, abilitabili o meno a
seconda di un flag, allora non stiamo parlando della stessa cosa.
Io penso, ad esempio, ad assert() che posso *compilare o meno* a
seconda di una define (NDEBUG, nel caso specifico).

Andrea Laforgia ha scritto:

Le assert sono prime cittadine nel linguaggio Java e si possono ignorare 
o meno con, immagino, la massima efficienza:
assert callWebService();
non dovrebbe costare nulla (sono ignorate) se non hai abilitato le 
assertion al momento dell'esecuzione.
A dire il vero non conosco i dettagli, per cui non sono sicuro che non 
costi veramente nulla.
Comunque generalmente preferisco così piuttosto che sparisca 
completamente dal compilato: come con il logging posso abilitarle o meno 
senza dover una libreria ad esempio.

 senza dover una libreria ad esempio.
Si e' perso un pezzo...senza dover ricompilare intendevo.

 "potenti" non mi piace) che in altri linguaggi?. 
E chi ha detto che sono altrettanto potenti?
-- 
Andrea Francia
http://andreafrancia.blogspot.com/2008/06/macross-frontier.html

senza dover una libreria ad esempio.
Il log è un altro discorso (non bisogna confondere la funzionalità di
run-time abilitabili/disabilitabili con quelle di compile-time per
scopi di debug). L'eliminazione dal compilato è un'ottima cosa in quei
linguaggi (tipicamente C/C++) in cui c'è attenzione per lo "small
footprint" delle applicazioni (vedi su sistemi embedded). In generale
io lo preferisco per il semplice principio che nell'eseguibile ci deve
essere il codice strettamente necessario all'applicazione ;-)

E chi ha detto che sono altrettanto potenti?
Allora mi sono perso qualche pezzo della discussione. L'OP inizia
chiedendo se in Java esiste qualcosa di simile alla compilazione
condizionale di altri linguaggi presi ad esempio. Tu dici che in Java
l'uso del preprocessore non è necessario, non molto utile, perché
tutti quegli aspetti che in altri linguaggi risolve il preprocessore
"sono già risolti in altri modi". Bada che non è a me che serve il
preprocessore, ma all'OP, per cui è a suo beneficio che cerco di
chiarire. Bene: se mi dici che Java già risolve certi aspetti, io
vorrei vedere come lo fa. Se mi dici che in Java il codice viene tutto
compilato, poi si procede banalmente ad abilitare/disabilitare parti a
run-time mediante flag, allora questo NON risolve lo stesso problema
del preprocessore. Se non sbaglio, in Java non c'è modo di rendere la
compilazione condizionale. Io uso la compilazione condizionale, in
altri linguaggi, per rendere compilabile un progetto come servizio di
Windows o, in alternativa, come applicazione normale, tanto per fare
un esempio. In Java non potrei fare la stessa cosa (è il principio che
conta, non l'esempio specifico).
Senza intenzione di polemica, mi danno solo fastidio quei "vai e fatti
del male" o "Java è più figo e non ti fa fare porcherie del genere"
che traspaiono (e sottolineo traspaiono, perché nessuno s'affretti a
dire "io non l'ho detto") da certi messaggi. 

 dire "io non l'ho detto") da certi messaggi. 
Senti, rispondi ai post che contengono queste frasi, se c'e' ne uno mio 
ti rispondo. Se qualcuno ha detto qualcosa che non ti piace rompi a lui 
non a me.
La polemica non mi interessa.
Io ho cercato di spiegare perché a mio avviso i progettisti di Java han 
deciso di non implementare alcune cose.
Per quel che mi riguarda Java, C e C++ sono strumenti con i loro difetti 
e i loro pregi. A me non me ne frega niente di dire che uno è migliore 
degli altri perché un discorso senza senso.
Lo strumento giusto dipende dal problema che devi risolvere.
Ho detto che la necessità per alcuni aspetti non è sentita come in C. 
Questo vuol dire che quegli aspetti non li risolve. Non mi sembra che 
questo voglia dire che un linguaggio è migliore dell'altro. Vuol solo 
dire che dato che certi aspetti non sono risolti quindi forse non è lo 
strumento giusto per risolvere quel tipo di problema.


Senti, rispondi ai post che contengono queste frasi
Andrea, io ho riportato frasi precise dei *tuoi* messaggi. Non quotare
solo quel che ti piace ;-) Rispondi sui contenuti tecnici senza
puntare il dito su fantomatiche polemiche. Neanche a me interessa
polemizzare né dare il via a guerre di religione sui linguaggi (ci
mancherebbe pure, visto che ne conosco e uso diversi, tutti i giorni).
Io sto parlando di aspetti tecnici. Vedi il messaggio precedente: tu
non hai propriamente detto che i progettisti Java hanno deciso di NON
IMPLEMENTARE certe cose, nel qual caso la risposta corretta sarebbe
stata: "in Java non si può fare". Punto. Hai tirato fuori la dubbia
utilità del preprocessore e detto che in Java le stesse cose si
possono fare "in altri modi". E' vero o non è vero che hai detto
questo? Mi fai vedere quali sono questi modi alternativi? E' in tutto
il thread che cerco di farti capire che gli "altri modi" di cui hai
parlato finora, non sono modi sostitutivi della compilazione
condizionale. Quindi - a beneficio dell'OP - la risposta più onesta e
corretta è che in Java non si può fare o si fa con tool aggiuntivi non
standard. Senza aggiungere gli orpelli sull'utilità o meno di
un'operazione del genere o sul "farsi del male" (cosa che NON hai
detto tu). Se poi si vuol fare un'analisi intellettualmente onesta su
quali sono le esigenze sentite o meno dagli utenti (affermazione che
tu hai fatto), bisognerebbe tener presente il numero di utenti che
passano magari ad altri linguaggi proprio perché NON riscontrano certe
caratteristiche. Dato di cui credo tu sia sprovvisto ;-) Insomma, è
come se un utente FIAT contento dicesse: "guardate quanta gente compra
la Punto! si vede che non sente il bisogno di qualcosa di diverso!"...
sì, ok, ma non tieni conto di quanta gente NON sceglie la Punto perché
necessita di qualcosa di diverso :-)

 conta, non l'esempio specifico).
In Java quello che può fare è avere una libreria di codice comune e due 
applicazioni diverse che usano la stessa libreria.


 puntare il dito su fantomatiche polemiche. 
Primo: rispondo a quello che ho voglia. Se voglio non rispondere a 
qualcosa non lo faccio.
Secondo: ero troppo incazzato perché qualcuno ha insinuato che sono uno 
di quelli che pensa che uno strumento sia meglio dell'altro in assoluto.
Terzo: ti ho risposto ai contenuti tecnici quando mi è passata.
Scusami se non rispondo al resto del messaggio, non l'ho letto, è 
scritto tutto di seguito e a me non piace leggere i post così. I post 
lunghi che non contengono i paragrafi non li leggo perché sono pigro.
E poi ho paura che ci sia qualcosa di polemico dentro e non voglio entrarci.


 Andrea, io ho riportato frasi precise dei *tuoi* messaggi. 
Hai riportato messaggi non miei.
Per quello ti ho detto di rispondere al messaggio specifico con il 
quoting. Per essere sicuro di quale post e quale frase stessi parlando.
Mi ha dato fastidio la prima volta, e poteva starci, ma almeno la 
seconda volta potevi ricontrollare di chi era il post.
Se c'e' una frase specifica di un post che non ti va bene e me ne vuoi 
chiedere conto: va bene, sarň felice di risponderti e confrontare le 
opinioni e eventualmente riconoscere di aver scritto qualche castroneria.
Pero', per piacere, rispondi al messaggio che contiene la frase che non 
ti piace, altrimenti io non ti rispondo.


  2. mettere funzioni inline
in C++ le costanti non dovrebbero mai essere definite con il pre-processore, 
non e' sicuramente una cosa "utile".
idem le funzioni inline, che oltre ad essere inutili (vedi keyword inline) 
sono anche pericolose per problemi intrinsechi del pre-processore.
Tommy 


Se fossi il signor C++ e non ci fossero problemi di compatibilità 
all'indietro toglierei le macro.
Per le constanti c'e' 'const', per le inline c'e' 'inline'.
Le altre cose del preprocessore possono rimanere.


 comunque istruzioni in piu'. Per il logging comunque va bene.
concordo quando chiami logger.debug() o che altro, il codice poi controlla 
se debug level e' enabled o meno. Quinidi in alcuni casi potresti avere una 
chiamata di funzione e poi un controllo per vedere se bisogna fare il 
logging o no. Con il pre-processore C++ (che e' sicuramente meno elegante e 
non puo' essere attivato/disattivato at run-time) elimini completamente il 
codice di logging e quindi e' per natura piu' efficiente.
concludo dicendo che il vero problema di log4j non e' tanto quanto detto 
sopra, ma il seguente:
logger.debug("Transaction for user " + username + " completed 
successfully!");
Beh,  anche se il metodo debug fa il controllo e se il logging e' 
disabilitato poi non fa nulla, e' cmq troppo tardi!
La concatenzazione delle 3 stringhe viene fatta prima di chiamare il metodo 
debug() poi debug() viene chiamato passando la stringa risultante, infine 
non fa nulla. Quindi spesso bisogna rendere il codice orribile facendo cose 
simili a:
if(logger.isDebugEnabled())
{
   logger.debug("Transaction for user " + username + " completed 
successfully!");
}
e questo e' un peccato in quanto rovina il codice che diventa meno elegante 
e poi lo stesso identico controllo viene poi fatto da debug().
Nel caso dell'esempio sopra il controllo non e' necessario e ci sono 
sicuramente metodi per risolvere in altro modo, ma l'esempio comunque espone 
un problema di log4j.
Tommy

 lunghi che non contengono i paragrafi non li leggo perché sono pigro.
Non è che sono pigro veramente. E che, anche quando scrivo le cose di 
getto, prima di spedirle cerco di dividere il testo in paragrafi, uno 
per argomento, per renderli (spero) piu' leggibili.
Non mi va di fare fatica a leggere il post di una persona che non ha 
usato la mia stessa cortesia nel confezionare il messaggio.
Un pigro lo sono comunque.


 assertion al momento dell'esecuzione.
Un minimo di costo potrebbe averlo visto che la prima parte dell'if viene 
comunque eseguita, immagino tale esecuzione sia velocissima e forse hotspot 
puo' fare miracoli, non so, pero' dire che il costo e' nulla e' forse un 
pochino troppo. Puoi dire che elimini completamente il costo di "expression" 
questo si!
Tommy

 compilazione condizionale.
Un modo vero e nativo non esiste, ma ci sono tanti modi non standard per 
farlo.
Gli "aspects" possono essere usati anche in questo modo (vedi ad esempio 
AspectJ). In alternativa si potrebbe usare un libreria di templating che in 
pratica funge da pre-processore oppure ad uno dei pochi pre-processori 
(alcuni usano sintassi pre processore C) dispobili per Java. In fine ci sono 
anche programmi che possono cambiare .class files e rimuovere alcune parti, 
etc...Se proprio vuoi potresti farlo tu direttamente usando la libreria 
BCEL, etc...  insomma il modo c'e'... ma non esiste un pre-compilatore 
standard per fare queste cose.
Tommy

 Secondo: ero troppo incazzato
;-)
Tommy


Chiedo scusa per il linguaggio.


 esecuzione sono molto lunghi ad esempio.
Ma questa e' una tua supposizione o cosa? Hai qualche link?
Io ho letto invece che il classloader elimina il codice di assertion
al momento del caricamento della classe. Quindi *dopo il caricamento*
costa 0.

On 10 Giu, 21:53, Andrea Laforgia

Di fatto pero' le assertion in Java funzionano cosi' e sono
funzionalita' di runtime.
A questo proposito mi sovviene in mente che anche in Java si puo'
avere compilazione condizinoale:
public static final boolean DEBUG = ...;
if (DEBUG) {
  //qualsiasi cosa
}
dovrebbe non essere incluso nel compilato, o almeno il compilatore e'
libero dicomportarsi cosi'.
Quindi  anche con le assert per eliminare il footprint si potrebbe
fare cosi:
if (ASSERT)
   assert ....;
Da fare se ci si trova in dispositivi con risorse limitate ;)
altrimenti e' una palla.

 e poi lo stesso identico controllo viene poi fatto da debug().
E' un problema del logging in generale (in Java almeno) non di log4j.
Comunque ci sono delle interessanti novita' a riguardo. Ad esempio in
Seam e' spesso possibile fare cose come
logger.debug("Transaction for user #{username} completed
successfully!");
dove non costa nulla perche' l'uso di EL elimina il bisogno di
concatenare. Ovviamente puoi farlo solo se hai una variabile username
da qualche parte ;)

 da qualche parte ;)
Beh il costo del concatenamento è sostituito dal costo della 
sostituzione, no?
Poi, senza conoscere Seam, mi viene da pensare che la sostituzione sia 
implementata con un concatenamento.


 libero dicomportarsi cosi'.
Non è vero nel caso che DEBUG venga definito in un'altra classe.


 costa 0.
Interessante.



E' vero, ho semplificato un po' troppo.
La reflection centra eccome: se prendi un'applicazione non banale e il
suo container (IoC o meno), scoprirai tante voci di configurazione del
tipo:
- pool di connessioni: devi specificare il driver da usare -> usa
Class.forName()
- implementazione dei servizi di persistenza: devi specificare che
motore usare -> usa Class.forName()
- ... devo andare avanti?
Certo, di per sè Class.forName() non è LA reflection, ma da lì parte
tutto.
Chiedo scusa ma non volevo far partire un piccolo litigio fra opposte
fazioni, volevo solo sottolineare come l'uso del preprocessore è alla
fine dei conti un "trucco", e come tutti i trucchi ha vita breve. Lo
verifico tutti i giorni da dieci anni a questa parte: per ogni secondo
guadagnato in CPU time, ci sono tanti bei bug che aspettano dietro
l'angolo. Questa situazione peggiora se qualcun'altro (che non sia
l'autore originale) deve mettere mano al codice: se c'è qualche
"trucco" la possibilità di sbagliare è sempre più alta.
Un certo signore diceva più o meno la stessa cosa, espressa in termini
diversi:
http://en.wikiquote.org/wiki/Donald_Knuth
Personalmente ritengo l'uso del pre-processore una ottimizzazione,
appunto, prematura e fonte quindi di bug.
Preparo l'estintore ora :)
--
www.megadix.it

On 11 Giu, 09:41, Andrea Francia

Non hai capito ;), si diceva che se il livello di logging non arriva a
debug e tu scrivi
logger.debug("user" + username);
stai evitando il logging ma non la concatenazione user  e username.
Se invece lo scrivi come
logger.debug("user #{uaserame}");
e il logging non e' su debug, stai anche evitando la concatenazione.


anche se faccio una static import?


Ho letto...non riesco neanche a documentare quindi prendilo con le
pinze per ora.

 
Ahh, vuoi dire che ci pensa il metodo debug a fare la sostituzione.
Pero' questo implica che username deve essere in qualche modo 
accessibile al sistema di logging.



Boh?



Comunque mi sembra ragionevolmente possibile.
Tanto di solito non ho a che fare con applicazioni dove questo costo è 
critico.


 condizionale.
Infatti non esiste nulla di simile in Java.
Ma il problema su cui e' continuata la discussione e': serve negli
ambiti con cui viene utilizzato Java?
Sapreste farmi un esempio dove il pre-processore e' veramente utile e
non se ne puo' fare a meno?
E anche ammesso che il pre-processore esista in Java, avrebbe senso
implementare tale esempio in Java?

 successfully!");
Beh, si, e'  un problema generale ma risolvibile e log4j non lo ha risolto.
Un modo abbastanza comune per risolvere in parte il problema e' quello di 
creare un wrapper intorno a logger (magari usando un factory)
Immagina di avere "MyLogger myLogger" che non e' altro che una classe con un 
logger privato e dei metodi che accedono ai metodi del membro privato. Poi 
scrivi dei metodi nuovi che fanno sostituzioni come ad esempio quella 
descritta sopra, o piu' semplice usando vararg e i soliti %s, %d etc...
A questo punto il mio esempio sarebbe:
myLogger.debug("Transaction for user %s completed successfully!", username);
ora il costo e' semplicemente quello di passare due cose a debug() (ma non 
fai concatenazione/sostitutione).
Poi myLogger.debug() fara' il controllo solito 
"if(internalLogger.isDebugEnabled())" ed nel caso sia enabled usera' i 
varargs per comporre la stringa da passare al .debug() del internalLogger.
Per finire bisogna assicurarsi che la gente non faccia concatenzioni ma usi 
questo metodo, quindi bisogna settare qualche regola in eclipse (ad esempio) 
che da errore se uno fa la concatenazione.
In generale pero', la maggior parte del codice che vedo in giro esternalizza 
ancora il conrtollo isDebugEnabled() rendendo il codice molto poco elegante 
(oppure non controllano rendendo lento anche quando non si e' in modalita' 
debug).
Tommy

 e fonte quindi di bug.
Ma, che il pre-processore sia spesso fonte di bugs siamo concordi. Che sia 
ottimizzazione prematura no... "prematura" nel senso utilizzato 
originariamente significa: prima di essersi accertati che sia necessaria.
Quindi, se hai fatto quello che dovevi fare e' ti sei accertato tale 
ottimizzazione sia necessaria, che tu usi il pre-processore o meno questa 
non e' per definizione piu' prematura.
Poi il pre-processore non viene solo utilizzato per le ottimizzazioni, anzi, 
in C++ questo uso e' sempre piu' raro... anzi praticamente sparito.
Tommy

 Boh?
direi che con un static import dovrebbe proprio funzionare.
Il problema e' che in C++ puoi fare:
#ifdef RUNNING_WINDOWS
   ... some calls to windows APIs
#endif
#ifdef RUNNIG_LINUX
   ... some calls to linux
#endif
il vantaggio e' che il pre-processore(come tu sai benissimo) viene invocato 
per primo e quindi il compilatore vede solo:
... some calls to windows APIs
se compiliamo per windows o:
... some calls to linux
se compiliamo su linux.
Nel caso di Java invece, anche se il compilatore e' furbo e rimuove le cose 
dal .class file risultante i paths irrangiungibili, il problema e' che tutto 
il codice deve essere in grado di compilare o ottieni errori di 
compilazione. In C/C++ invece se tu hai definito RUNNING_WINDOWS allora 
dentro a RUNNING_LINUX puoi avere roba che non compila. Questo perche' il 
compilatore viene invocato solo dopo alle sostituzioni del pre-processore.
Java pero' non ha problemi di dover supportare varie platforms di solito... 
quindi il problema si pone meno. Ma magari vorresti pero' avere una cosa 
simile per decidere se usare una libreria di compressione piuttosto che 
un'altra senza dover per forza includere entrambe, o dover scaricare 
entrambe, (nota che gli imports non possono essere messi in IFs in Java), 
oppure ancora qualche altra cosa, si possono fare vari esempi di casi in cui 
la compilazione condizionale (vera, fatta da un pre-processore) potrebbe 
essere utile.
Ovvero in Java non puoi avere:
if (DEBUG) {
    __CODICE_CHE_NON_COMPILA___
}
anche se DEBUG e' definito come static final boolean come false.
Ma nessuno ti evita di usare un pre-processore con Java, anche se non sono 
standard... :-(
Tommy

 direi che con un static import dovrebbe proprio funzionare.
Vorrei vedere con un decompilatore se è proprio vero.
Appena ho un po' di tempo provo.


 costa 0.
Potresti forse avere anche ragione, visto che ho letto cosi' anche io.... 
Pero' non ne siamo sicuri nessuno dei due...
Quello di cui sono certo e' che l'assertion finisca nel .class file e ci 
finisce nel formato che ho descritto sopra. Poi pero' il class loader 
potrebbe riconoscere le assertions e rimuoverle...  in pratica non sono 
sicuro...
Dato:
public class UnaClasse {
    public UnaClasse(final int value) {
        assert value != 0;
    }
}
Questo e' quello che vede il class loader:
public class UnaClasse
{
public UnaClasse(int i)
{
//  0    0:aload_0
//  1    1:invokespecial   #1   <Method void Object()>
    if(!$assertionsDisabled && i == 0)
//* 2    4:getstatic       #2   <Field boolean $assertionsDisabled>
//* 3    7:ifne            22
//* 4   10:iload_1
//* 5   11:ifne            22
        throw new AssertionError();
//  6   14:new             #3   <Class AssertionError>
//  7   17:dup
//  8   18:invokespecial   #4   <Method void AssertionError()>
//  9   21:athrow
    else
        return;
// 10   22:return
}
static final boolean $assertionsDisabled =
   !mioPackage/UnaClasse.desiredAssertionStatus();
static
{
//  0    0:ldc2            #5   <Class UnaClasse>
//  1    3:invokevirtual   #6   <Method boolean 
Class.desiredAssertionStatus()>
//  2    6:ifne            13
//  3    9:iconst_1
//  4   10:goto            14
//  5   13:iconst_0
//  6   14:putstatic       #2   <Field boolean $assertionsDisabled>
//* 7   17:return
}
}
Durante il loading della classe viene controllato il 
desiredAssertionStatus() e si salva il valore appropriato in 
$assertionsDisabled.
Questa e' una static final boolean, ma e' troppo tardi per rimuoverla dal 
.class file... visto che e' gia' stato prodotto
Il codice all'interno del costruttore poi semplicemente controlla il valore 
di $assertionsDisabled e si comporta di conseguenza... Che questo codice 
venga eseguito o meno (rimosso in fase di loading dal class loader) non lo 
so.
A questo punto mi sorge un dubbio, quando abbiamo letto che viene rimossa 
dal class loader intendevano che il class loader controlla se le assertions 
sono on o off e nel caso in cui siano off settano un flag che grazie al 
short-circuiting evita di dover fare la evaluation della espressione? Oppure 
intendevano davvero che il class loader puo' dal byte code che sta caricando 
rimuovere pezzi che capisce non verranno mai eseguiti?
In teoria questa seconda ipotesi e' possibile, ma questo in pratica avviene? 
E' una cosa che viene lasciata libera o definita dalle specifiche? E' di 
solito implementata?
Sappiamo che la prima fase di compilazione puo' rimuovere codice non 
utilizzato e sappiamo che hotspot puo' fare cose simili at runtime, ma devo 
ancora trovare un documento chiaro che mi dice che anche il class loader 
faccia cose simili (in teoria il class loader deve caircare la classe nel 
piu' breve tempo possibile, quindi nonostante sia possibile fare 
ottimizzazioni e rimozioni varie anche at-class-loading-time non sono 
convinto che questo necessariamente avvenga. Sono sicuro pero' che poi 
hotspot si dia da fare e faccia la sua magina quando decide che una classe 
non debba piu' essere interpretata).
Tommy

 in C++ questo uso e' sempre piu' raro... anzi praticamente sparito.
Io purtroppo ho potuto usare C e C++ solo quando ero un pischello, ho
combinato solo un sacco di casini e alla fine usavo il C++ come Java,
però senza conoscere Java. Quello che succedeva spesso è che i miei
programmi C++ si trasformavano in un "Domain Specific Language" o DSL,
nome in voga oggi: risparmiavo sì un sacco di tempo a scrivere i
programmi, peccato che li sapessi modificare solo io... e qui si torna
al discorso sui "trucchi": troppe macro e ammennicoli vari diventano
un problema quando ci lavorano n >= 2 persone.
--
www.megadix.it

 Appena ho un po' di tempo provo.
Appena fatto ora. Il codice viene rimosso. Questo significa che se la classe 
che hai importato cambia devi assolutamente ricompilare il codice della 
classe che fa l'import!
Tommy

          
Ho fatto un po' di prove e, sorpresa, sorpresa, funziona sia con 
l'import che con l'import static.
In pratica se due classi:
package debug;
public class Debug {
     public static final boolean enabled = true;
}
package prova;
import debug.Debug;
public class Main {
     public static void main(String[] args) {
         if(Debug.enabled) {
             System.out.println("enabled!");
         } else {
             System.out.println("not enabled!");
         }
     }
}
Compili tutto ed esegui la Main. Risultato:
enabled!
Cambi enabled=false in Debug.java, ricompili *solo* Debug.java e 
riesegui e ottieni ancora:
enabled!
Quindi quando import una variabile final da un'altra classe nel 
compilato viene inserito il valore che aveva la variabile durante la 
compilazione, se poi cambi la variabile e non ricompili la classe che 
importa il cambio non si vede. Indipendentemente dall'uso di static 
import o import normale.
Quindi, diversamente da quello che avevo detto io, se uno scrive
public static final boolean DEBUG = ...;
if (DEBUG) {
   //qualsiasi cosa
}
è verosimile che il corpo dell'if non venga inclusa nel compilato a 
seconda del valore di DEBUG.
Quindi sembra verosimile che Java supporti un qualcosa di simile alla 
compilazione condizionale.
A differenza della compilazione condizionale vera e propria, come quella 
del pre-processore C e C++, la parte esclusa deve essere comunque 
compilabile. In pratica non si puo' fare questo:
if (DEBUG) {
   codice che non compila ...



Ho fatto ulteriori prove, ho provato trasformando il campo in un metodo 
final.
package debug;
public class Debug {
     public static final boolean enabled() {
         return true;
     }
}
package staticimport;
import debug.Debug;
public class Main {
     public static void main(String[] args) {
         if(Debug.enabled()) {
             System.out.println("enabled!");
         } else {
             System.out.println("not enabled!");
         }
     }
}
In questo caso la classe compilata Main.class mantiene entrambi i 
comportamenti.


Scusate se mi intrometto nel thread, volevo fare un paio di
osservazioni:
1) lo static import è una funzionalità del linguaggio java, non a ha
che fare con il bytecode generato. Insomma è uno shortcut, ma il
compilatore lo tratta ESATTAMENTE come se avessi usato il nome della
classe che contiene il metodo/campo statico.
2) Cosa fa il compilatore dipende... dal compilatore. La Sun non
dichiara cosa si deve fare nel caso il codice non sia raggiungibile.
Quindi javac SUN elimina il corpo dei blocchi irraggiungibili, ma gli
altri non è detto. Da notare che ci sono dei compilatori (quello di
Eclipse, ad esempio) che *sono in grado di compilare codice che non
compila*! Nel senso che sono in grado di produrre il bytecode di una
classe con errori di sintassi al suo interno (son sicuro per quanto
riguarda il corpo dei metodi, non so in altre circostanze...). Credo
che in quei casi sostituisca il corpo del metodo con un throw new
UresolvedCompilationError, che deriva da RuntimeError. Anche jasper
(credi si chiami così, il compilatore delle jsp di Tomcat)credo si
comporti così.  Di sicuro il codice con l'errore non va, ma se non lo
invochi non causa problemi
3) Anche a me non è chiaro lo ise case del preprocessore (solo perché
non ho mai proggrammato in C/C++!) ma i casi da te citati secondo me
non sono casi da preprocessore:
3.1) Caso di libreria da scegliere a runtime. E' il classico uso della
reflection. Il tuo codice non dovrebbe invocare la libreria
direttamente, ma una interfaccia. Sarà poi un DI a far lavorare le
cose al posto tuo. In questo caso, rimuovi completamente la dipendenza
della libreria dal tuo codice, e sei libero di compilare anche senza
la presenza della libreria stessa. (Puoi replicare che tutte le
librerie devono implementare la stessa interfaccia, cosa che può non
essere nel caso di lib non standard, che so, per la produzione di PDF.
A questo preventivamente rispondo che cmq tu se vuoi utilizzare
librerie diverse per fare la stessa cosa, implicitamente stai definedo
una interfaccia+degli adaptor per farla funzionare. Se disaccoppi il
codice in modo opportuno (e te lo consiglio) avrai la dipendenza dalla
libreria solo nel codice che la usa.)
3.2) Caso di piattaforme differenti. E il paradigma Write once run
everywhere? In ogni caso vale il 3.1: il codice platform dependent lo
metti in na classe a parte, e poi istanzi via reflection (tramite DI o
Factory) la classe per la tua piattaforma. Ovviamente scriverai una
interfaccia comune, e magari un sistema di capabilities in modo da
informare il sistema esterno di cosa supporti e cosa no...
Hai altri casi di uso? Non è che mi diverto a smontarli (beh, un
pochino.. mi stimola ;) ), ma soprattutto sono curioso sull'impiego
perché sebbene io sappia di che tratta il preprocessore, non ne ho MAI
sentito la mancanza, e mi chiedo a che possa servire.
4) Per altre cose che mi possono venire in mente, continua a venrimi
in mente l'accoppiata AOP + Annotations. In effetti un po' al
preprocessore ci assomiglia. Io l'ho sempre visto come post
processore, ma in effetti se non ricordo male AspectJ lavora un po'
come un preprocessore (interviene sulla compilazione). Anzi, col senno
di poi potrei dirti che il preprocessore java esiste e si chiama
AspectJ
un cosiglio: dai una occhiata a Guice, o a Spring, se vuoi dare una
occhiata ad un modo elegante di fare reflection o AOP in modo
dichiarativo

 sentito la mancanza
Neanch'io. Non confondermi con l'altro Andrea che ha partecipato al 
thread. Con cui tra l'altro ho avuto da ridire.


 dichiarativo
Faro', grazie, anche se dover usare un framework come Spring forse per cose 
semplici e' un overkill!
Tommy

 indicare in modo esplicito come.
Tranquillo penso si riferisse ai miei esempi e non ai tuoi!
Tommy

 Tommy
Ooop ho messo la signature troppo presto, il post continuava anche dopo la 
signature!

 
E' perché uso Netbeans di solito.
Questa cosa di Eclipse poi la provo, grazie.


 at Main.main(Main.java:16)
Ahah, nemmeno mi sono letto la exception, chiaramente questo e' dovuto ad un 
mio errore... rifaccio:
public final class Main {
 public static void main(String[] args) {
  System.out.println("Hello world!");
  badMethod();
 }
 public static void badMethod()
 {
  djjsdfsd;
 }
}
ora che anche badMethod e' static...
Otteniamo il giusto output:
Hello world!
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
 Syntax error, insert "AssignmentOperator Expression" to complete Expression
 djjsdfsd cannot be resolved
 at Main.badMethod(Main.java:21)
 at Main.main(Main.java:16)
Scusate se avevo scritto di fretta e non avevo nemmeno controllato la 
exception!!!
Tommy


Non parlo di EL, ma delle classi java che vengono generate dalla
compilazione delle JSP. E quelle sono proprio java!! (vengono
tramutate in servlet, se non ricordo male)
DA QUI IN POI:
Scusami Andrea, ho sbagliato alla grande! Volevo rispondere a Tommy,
ma ho sbagliato post a cui rispondere.... è che il mio client (Google
Groups) mi fa vedere il thread in piano. :(


 Groups) mi fa vedere il thread in piano. :(
Ah, ok. Fa niente.


 Spero di non averti confuso ulteriormente le idee...
Sono dìaccordo su quasi tutto quello che dici ma le macro C usate bene 
sono un livello in più di metaprogrammazione.
Poi vi ricordo le "annotation" introdotto dopo la 1.6 .. cosa sono se 
delle direttive al compilatore?
Saluti
-- 
Il mio nome è legione

 delle direttive al compilatore?
Le annotation sono qualcosa di diverso.
Solo alcune specifiche annotation sono direttive per il compilatore, 
come ad esempio la @SuppressWarning.
In generale le annotation sono un modo per aggiungere meta dati alle 
classi. Molte annotation esistono solo per essere lette a runtime da 
entità che non hanno a che fare niente con il compilatore.
-- 
Andrea Francia
http://andreafrancia.blogspot.com/2008/06/relazioni-molti-molti-con-jpa.html