====== Reificazione ====== //Reificazione, si è una parola Italiana ...// PREV [[evoluzione_non_rivoluzione]] ===== Defnizioni di reifcazione ===== Processo mentale mediante il quale a concetti astratti viene assegnata consistenza di cose concrete Nella flosofa di Marx, processo secondo cui nell'economia capitalistica l'uomo e il suo lavoro sono ridotti al valore della merce che producono La reifcazione è una fallacia o un'ambiguità quando un'astrazione (una credenza astratta o un costrutto ipotetico) viene trattata come se fosse un concreto evento reale o un'entità fsica Nell'ambito dell'Ingegneria della conoscenza, e in particolare della defnizione di ontologie, la reifcazione è una rappresentazione indiretta che prevede l'utilizzo di determinate espressioni del linguaggio per descrivere entità del mondo reale intuitivamente associate a espressioni di tipo diverso. L'esempio tipico di reifcazione è costituito dall'utilizzo di individui per rappresentare classi. Nel contesto della programmazione orientata agli oggetti si defnisce reifcazione il procedimento di creazione di un modello di dati basato su un concetto astratto predefnito. Mediante la reifcazione, un computer può compiere elaborazioni riguardanti un'entità astratta come se si trattasse di un insieme qualsiasi di dati di altro tipo ===== Unchecked cast ===== Non sempre il compilatore è in grado di capire se un cast verso un tipo non reifcabile avrà successo I sistemi di tipi (dei linguaggi di programmazione orientati agli oggetti) non sono perfetti e non possono individuare situazioni di successo come può fare un (buon) programmatore Per questo motivo un cast verso un tipo non reifcabile non genera un errore ma un warning ===== In java ===== In java un tipo è reifcabile se il tipo è completamente identifcabile a runtime, ovvero se la type erasure non rimuove informazioni utili ===== Tipi reifcabili ===== * Primitivi es: int * Classi o interfacce non parametriche es: String, Comparable * Tipi parametrici in cui tutti gli argomenti di tipo sono wildcard non limitati es: List o Map * Raw type es: List, Map Array di elementi di tipo reifcabile es: int[] , List[] ===== Tipi non riefcabili ===== * Variabili di tipo es: T in Xxxx * Tipi parametrici con parametri attuali es: List, Comparable * Tipi parametrici con un limite es: List , Comparable ===== Note ===== In java il tipo di un array viene reifcato con il tipo dei suoi componenti Un tipo parametrico non viene reifcato con il suo parametro di tipo List è equivalente a List (nel senso di passaggio di parametri) ma il primo è reifcabile il secondo no ===== Instance test e cast ===== I test instanceof ed i cast dipendono dall'esame a runtime dei tipi degli oggetti coinvolti e quindi dalla reifcazione Test di istanza verso un tipo non reifcabile → errore (di compilazione) Cast ad un tipo non reifcabile → genera (di norma) un warning public class Myinteger { private final int value; public boolean equals(Object o) { Myinteger è reificabile → il cast non genere warning if (o instanceof Myinteger){ // ynteger è reificabile → compila return this.value == ((Myinteger)o).value; } else return false; // Myinteger è reificabile → il cast non genere warning } ... } ===== Equals su liste ===== public abstract class MiaLista extends AbstractCollection implements List{ public boolean equals(Object o){ if ( o instanceof List){ Iterator it1 = iterator(); Iterator it2 = ((List)o ).iterator(); while (it1.hasNext() && it2.hasNext()){ E e1 = it1.next(); E e2 = it2.next(); if (! ( e1 == null ? e2== null: e1.equals(e2) ) ){ return false; } } } } return !it1.hasNext() && !it2.hasNext(); } else return false; ===== Equals su liste: analisi ===== public abstract class MiaLista extends AbstractCollection implements List{ public boolean equals(Object o){ if ( o instanceof List){ Iterator it1 = iterator(); // Errore di compilazione! List non è reificabile Iterator it2 = ((List)o ).iterator(); while (it1.hasNext() // Unchecked cast warning! && it2.hasNext()){ ... ===== Equals su liste: versione fxata ===== public abstract class MiaListaOK extends AbstractCollection implements List{ Iterator it1 = iterator(); Iterator it2 = ((List)o ).iterator(); while (it1.hasNext() && it2.hasNext()){ return false; } } } return !it1.hasNext() && !it2.hasNext(); } else return false; ==== Analisi ==== public abstract class MiaListaOK extends AbstractCollection implements List{ public boolean equals(Object o){ if ( o instanceof List){ Iterator it1 = iterator(); // OK List è reificabile Iterator it2 = ( (List)o ).iterator(); // List è reificbaile e non vengono generati warning while (.... Object e2 = it2.next(); // Da una List posso prelevare Object senza problemi ===== Cast non reifcabili ===== Test di istanza verso tipi non reifcabili generano sempre errore In alcune circostanze un cast ad un tipo non reifcabile può non generare warning ==== Nessun warning ==== public static List asList(Collection c ) throws IllegalArgumentException { if ( c instanceof List){ // List è reificabile → compila return (List)c; } else throw new // Il cast non genera waring in quanto la sorgente del cast ha tipo Collection // e ogni oggetto di questo tipo che implementa List deve avere come tipo List IllegalArgumentException("Il parametro passato non e' un sottotipo di List"); public static List converti(List oggetti){ for (Object obj: oggetti){ //Il cast “a logica” non fallirà mai if (!( obj instanceof String)){ throw new IllegalArgumentException( ... // OK String è reificabile }} return (List)(List)oggetti; } // Unchecked Cast ← il compilatore non è in grado di capire se il cast avrà successo o meno **Nota: è illegare “castare” una lista di oggetti ad una lista di stringhe, quindi serve il doppio cast ** ===== Array e reifcazione ===== Gli array reifcano i loro componenti ovvero conservano a runtime i tipi dei loro componenti ==== Un vecchio esempio ==== Integer[] interi = new Integer[] {1,2,3}; // OK, gli array sono covarianti Number[] numeri = interi; numeri[2] = 3.14; // ArrayStoreException Double non è compatibile con il tipo reificato dell'array ==== Creazione di array ==== public static T[] toArray(Collection c){ T[] ret= new T[c.size()]; // NO! errore di compilazione int i = 0 ; for (T x :c){ret[i++] = x;} return ret; } Le variabili di tipo non sono reificabili → viene generato un generic array creation error Cannot create a generic array of T ==== Difetti ... ==== Non poter creare array di generics è una limitazione di java Array generici sono problematici a causa della erasure (tuttavia) erasure facilita l'evoluzione In generale ... dire “no!” ad array ed utilizzare il Collection Framework ==== Refection ... ==== Tramite refection è possibile ovviare al problema della creazione di array generici ==== Dont' try this at home ==== public static T[]toArray(Collection coll){ T[] ret = (T[]) new Object[coll.size()]; // Unchecked Cast! int i = 0 ; for (T x :coll){ret[i++] = x;} return ret; } --- List stringhe = ... String[] a = toArray(stringhe); // Class Cast Exception Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; at generics.cap6.Ex1.main(Ex1.java:23) ==== Messaggio oscuro ==== Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; at generics.cap6.Ex1.main(Ex1.java:23) * L signifca array di reference type * [LObject signifca array di Object, Object è il component type dell'array * L'errore non viene segnalato nel punto in cui viene generato (!) ma in un altro punto (!!!) ovvero nel main ==== Versione generata dall'erasure: analisi ==== public static Object[] toArray1( Collection coll){ Object[] ret = (Object[]) new Object[coll.size()]; // Unchecked Cast sparito! --> Erasure: converte il cast a T[] in un Cast a Object[] int i = 0 ; for (Object x :coll){ ret[i++] = x;} return ret; } --- List stringhe = Arrays.asList("ciao","mondo"); String[] a = (String[])toArray(stringhe); //ClassCastError --> Erasure: inserisce il cast a String[] **Attenzione! Nonostante l'array contenga solamente stringhe, il suo tipo reifcato è un array di Object! ** ==== Cast iron guarantee (ancora) ==== I cast inseriti dall'erasure non falliscono mai a parte quando viene generato un unchecked cast warning Quando viene generato un unchecked cast warning allora i cast inseriti dalla erasure * Possono fallire * Possono essere segnalati in parti del codice diferenti da quella che ha generato l'errore ===== Adoro i soldi che generano i soldi ===== A volte un modo per fare soldi è tramite altri soldi. Lo stesso si può applicare agli array: generare array tramite un altro array public static T[] toArray( Collection coll, T[] arr){ T[] ret = null; ret = (T[])java.lang.reflect.Array.newInstance (arr.getClass().getComponentType(), // unchecked cast coll.size()); int i = 0; for (T elem: coll) ret[i++] = elem; return ret; } } ==== Esecuzione del codice ==== List a= Arrays.asList("ciao","a"); String[] st = toArray(a, new String[0]); for (String s: st) System.out.println(s); * Ok! Funziona! * Il metodo getCoponentType() restituisce un “Class Object” che rappresente il tipo dei componenti dell'Array T * Class ctype = arr.getClass().getComponentType(); Nel nostro caso è String ==== La versione "di classe" ==== public static T[] toArray( Collection coll, Class classse){ T[] ret = null; ret = (T[])java.lang.reflect.Array.newInstance ( Classse, coll.size() ); int i = 0; for (T elem: coll) ret[i++] = elem; return ret; } List a= Arrays.asList("ciao","a"); String[] st2 = toArray(a, String.class);