Il contenuto di questo sito è rilasciato sotto licenza Creative Commons License se non specificato diversamente

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<T>
  • Tipi parametrici con parametri attuali es: List<String>, Comparable<Integer>
  • Tipi parametrici con un limite es: List<? extends String> , Comparable <? super Number>

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<? extends Object> (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
} ...
}
</code java>
 
===== Equals su liste =====
<code>
public abstract class MiaLista<E> extends AbstractCollection<E> implements List<E>{
public boolean equals(Object o){ if ( o instanceof List<E>){
Iterator<E> it1 = iterator(); Iterator<E> it2 = ((List<E>)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<E> extends AbstractCollection<E> implements List<E>{
public boolean equals(Object o){ if ( o instanceof List<E>){ Iterator<E> it1 = iterator();  // Errore di compilazione! List<E> non è reificabile
Iterator<E> it2 =
((List<E>)o ).iterator(); while (it1.hasNext() // Unchecked cast warning!
&& it2.hasNext()){ ...

Equals su liste: versione fxata

public abstract class MiaListaOK<E> extends AbstractCollection<E> implements List<E>{
Iterator<E> 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<E> extends AbstractCollection<E> implements List<E>{ public boolean equals(Object o){
if ( o instanceof List<?>){ Iterator<E> 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 <T> List<T> asList(Collection<T> c )
throws IllegalArgumentException { 
 if ( c instanceof List<?>){ // List<?> è reificabile → compila
return (List<T>)c; } else throw new // Il cast non genera waring in quanto la sorgente del cast ha tipo Collection<T> 
                                    // e ogni oggetto di questo tipo che implementa List deve avere come tipo List<T>
 
IllegalArgumentException("Il parametro passato non e' un sottotipo di List<T>");
public static List<String> 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<String>)(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> T[] toArray(Collection<T> 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> T[]toArray(Collection<T> coll){
T[] ret = (T[]) new Object[coll.size()];  // Unchecked Cast!
int i = 0 ;
 for (T x :coll){ret[i++] = x;} 
return ret;
} --- 
List<String> 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<String> 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>
 T[] toArray( Collection<T> 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<String> 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> T[] toArray( 
Collection<T> coll, Class<T> 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<String> a= Arrays.asList("ciao","a");
String[] st2 = toArray(a, String.class);
 
java/generics/reificazione.txt · Ultima modifica: 2012/03/11 12:06 da fcasadei
 
Recent changes RSS feed