2011-01-26 13 views
5

In Scala/Java (~ sulla JVM), ci sono alcuni casi più piccole dove il comportamento è diverso come:Quali ragioni esistono per le differenze tra i tipi di tempo di compilazione e i tipi di runtime?

/* "Dynamic" cast */ 
"".getClass.cast("Foo") 
//res0: Any = Foo 

/* "Static" cast */ 
classOf[String].cast("Foo") 
//res1: String = Foo 

/* "Compile time cast" */ 
"Foo".asInstanceOf[String] 
res2: String = Foo 

In quali lingue è il divario tra il tempo di compilare ed eseguire il tempo è grande e ci sono ragioni da un linguaggio design POV perché questa potrebbe essere una "cosa buona"?

andando verso la direzione opposta: C'è un (a tipizzazione statica) lingua senza alcuna differenza tra il tempo di compilare ed eseguire i tipi di tempo?

risposta

6

La ragione per il primo risultato è che il metodo getClass ha la seguente firma in Java

public final Class<?> getClass() 

che eredita Scala. Mentre noi sappiamo che se chiamiamo getClass su un riferimento di tipo T della firma potrebbe essere

public final Class<? extends T> getClass() 

il compilatore non lo fa. Si potrebbe immaginare che qualche estensione lingua per fornire un tipo speciale che rappresenta il tipo statico del ricevitore che permetta

public final Class<? extends Receiver> getClass() 

o una sorta di involucro speciale nel compilatore per getClass. Sembra infatti che Snoracle Java sia davvero un caso speciale getClass ma non sono sicuro che sia richiesto dalla specifica del linguaggio Java. Tuttavia, se si dispone di un riferimento di un particolare tipo statico T, non c'è motivo per cui non si possa fare l'equivalente T.class (java) o classOf[T] (scala). In altre parole tale estensione non porterebbe alcun potere espressivo maggiore ma complicherebbe l'implementazione della lingua.

Per quanto riguarda il "cast di tempo compilato" rispetto al "cast" statico ", non c'è davvero alcuna differenza. Sarebbe corretto per un compilatore di desugar x.asInstanceOf[T] a classOf[T].cast(x).

Qualsiasi lingua con sottotipo ha la possibilità che il tipo di riferimento noto staticamente sia meno specifico del tipo del valore a cui fa riferimento. Le lingue con sistemi di tipo statico che non hanno sottotipi di solito non hanno un concetto di tipi di runtime in quanto esiste un solo tipo effettivo che risiede in un determinato tipo di nome. In questi linguaggi i tipi vengono cancellati in fase di esecuzione, nello stesso modo in cui i parametri di tipo vengono cancellati sulla JVM.

Spero che questo aiuti a comprendere i tipi di riferimenti statici rispetto al tipo di valori di runtime.

1

C non ha informazioni di tipo runtime (RTTI). Quindi il tipo statico è il tipo di runtime. Più precisamente ciò consente al compilatore di eliminare del tutto le informazioni sul tipo dal file oggetto e genera un codice più veloce (nessun controllo durante l'esecuzione del programma richiesto). Per il collegamento le informazioni sono nelle intestazioni.

In C++ RTTI esiste solo con l'ereditarietà virtuale/classi di base astratte, che è un idioma scoraggiato a causa di prestazioni non buone (dagli standard C++).

In Java (per quanto posso ricordare) l'idioma preferito (almeno 7 anni fa) era quello di utilizzare un'interfaccia molto generale. Ciò significa che non ci sono molte informazioni sul tipo in fase di compilazione. E ovviamente i generici in Java hanno tutti gli oggetti come tipo statico. Quindi tutte le informazioni sono di runtime (con l'overhead corrispondente).La ragione di ciò sembra essere che il sistema di tipo statico sia troppo rigido (C, Pascal) e necessita di lacune (void *) o relativamente complesso (C++, Haskell).

In Haskell il tipo di compilazione è in genere il tipo di runtime, tranne il caso di tipi di ordine superiore e del tipo esistenziale. GHC per qualche ragione (riflessione? Istanza di classe di tipo?) Anche se non usa questo per guadagni di efficienza. Quindi il tipo di informazioni è tutto runtme.

Problemi correlati