Java è semplice, una cosa che si sente spesso, specialmente nelle università italiane che per qualche ragione sono in fissa con l’object orientation, ma non voglio parlare di questo.
Voglio portare un’esempio per me significativo, implementare l’intersezione tra insiemi in java, utilizzando le classi standard di java, quindi java.collection.Set
e java.collection.HashSet
, ed i generics di java 1.5.
La prima cosa da fare è scegliere la firma del metodo
public <T> Set<T> intersection(Set<T> s1, Set<T> s2) {
....
}
Questa in linea di massima potrebbe sembrare ok però ha un design flaw, è troppo restrittiva, ci sono combinazioni di Set sui quali si dovrebbe poter fare un’intersezione ma il metodo non accetta i parametri.
Se prendiamo Set<Number> s1 = {1, 2.0, 3.14159}
e Set<Double> s2 = {3.14159, 2.0}
(non è possibile inizilizzare insiemi con questa sintassi, però scrivere proper java richiede troppo testo) non vengono accettati dal metodo con la firma proposta, però teoricamente è del tutto possibile fare l’intersezione di questi due insiemi, di fatti è {3.14159, 2.0}
.
Ecco un’altra proposta:
public <T> Set<T> intersection(Set<T> s1, Set<? extends T> s2) {
....
}
Questa già ha dei vantaggi in più, ora il controesempio di prima con Number e Double funziona, ma c’è ancora qualcosa che sfugge, ecco un’altro controesempio:
Set<Number> s1 = {1, 2.0, 3.14159}
e Set<Object> s2 = {"c > c++ == true", 3.14159, false}
, l’intersezione tra questi due insiemi è del tutto possibile (il singleton { 3.14159 }
), ma il metodo non lo accetta.
Saltando direttamente alla conclusione, vi mostro direttamente la scelta migliore e anche l’implementazione (se poi qualcuno è interessato si può continuare la discussione su tutti i dettagli ed altre possibili firme):
public <T> Set<T> intersection(Set<? extends T> s1, Set<?> s2) {
Set<T> result = new HashSet<>();
for (Object o : s2) {
if (s1.contains(o)) {
result.add(o);
}
}
return result;
}
Ora perchè fare tutto questo discorso?
Per mostrare quanto anche solo la scelta della firma di un metodo può essere complicata in java, in altre parole java non è semplice, ma ci viene detto che lo è, di solito da persone che non si sporcano le mani con il codice da anni.
Una piccola euristica che mi piace seguire è “Non fidarti di chi non si mette in gioco”.
Non sono qui per dire che java è un cattivo linguaggio, chiariamoci lo penso e posso argomentare a riguardo, ma è un buon esempio per mostare quanto sono complicate le astrazioni ed i luoghi comuni anche in informatica.