Perché a tempo di compilazione tecniche generative per la tipizzazione strutturali impediscono compilazione separata?

StackOverflow https://stackoverflow.com/questions/3498954

  •  29-09-2019
  •  | 
  •  

Domanda

I stava leggendo (ok, skimming) Dubochet e Odersky di Compilazione strutturali su la JVM ed è stato confuso dalla seguente affermazione:

tecniche generative creano interfacce Java di stare in per i tipi strutturali sulla JVM. La complessità di tale tecniche consiste nel fatto che tutte le classi che devono essere utilizzate come tipi strutturale qualsiasi punto del programma deve implementare le interfacce giuste. Quando questo viene fatto al momento della compilazione, è impedisce compilazione separata.

(enfasi aggiunta)

Si consideri l'esempio autoclose dalla carta:

type Closeable = Any { def close(): Unit }

def autoclose(t: Closeable)(run: Closeable => Unit): Unit = {
   try { run(t) }
   finally { t.close }
}

Non potremmo generare un'interfaccia per il tipo Closeable come segue:

public interface AnonymousInterface1 {
   public void close();
}

e trasformare la nostra definizione di autoclose a

// UPDATE: using a view bound here, so implicit conversion is applied on-demand
def autoclose[T <% AnonymousInterface1](t: T)(run: T => Unit): Unit = {
   try { run(t) }
   finally { t.close }
}

quindi prendere in considerazione un invito-site per autoclose:

val fis = new FileInputStream(new File("f.txt"))
autoclose(fis) { ... }

Dal momento che è un fis FileInputStream, che non implementa AnonymousInterface1, abbiamo bisogno di generare un wrapper:

class FileInputStreamAnonymousInterface1Proxy(val self: FileInputStream) 
      extends AnonymousInterface1 {
   def close() = self.close();
}

object FileInputStreamAnonymousInterface1Proxy {
   implicit def fis2proxy(fis: FileInputStream): FileInputStreamAnonymousInterface1Proxy =
      new FileInputStreamAnonymousInterface1Proxy(fis)
}

Devo mancare qualcosa , ma non è chiaro per me quello che è. Perché questo approccio eviterebbe compilazione separata?

È stato utile?

Soluzione

Io in realtà utilizzare l'approccio implicito (usando typeclasses) si descrive nel Scala ARM biblioteca . Ricordate che questa è una soluzione codificato a mano al problema.

Il più grande problema qui è la risoluzione implicita. Il compilatore non genera wrapper per te al volo, è necessario farlo prima del tempo e assicurarsi che siano uno l'ambito implicito. Questo significa (per Scala-ARM) che forniamo wrapper "comune" per tutte le risorse che possiamo, e ridotti a tipi di riflessione-based quando non riusciamo a trovare il wrapper appropriata. Questo dà il vantaggio di permettere all'utente di specificare il proprio involucro utilizzando le normali regole implicite.

See: Il Tipo di risorsa-trait e tutto di esso è predefinito involucri.

Inoltre, ho bloggato su questa tecnica che descrive la magia risoluzione implicita in modo più dettagliato: Scimmia Patching, duck typing e classi di tipo .

In ogni caso, probabilmente non si vuole mano-codificare un ogni tipo di classe si utilizzano tipi strutturali. Se effettivamente voleva il compilatore per creare automaticamente un'interfaccia e fare la magia per voi, si potrebbe ottenere disordinato. Ogni volta che si definisce un tipo strutturale, il compilatore dovrà creare un'interfaccia per esso (da qualche parte nell'etere, forse?). Ora abbiamo bisogno di aggiungere spazi dei nomi per queste cose. Inoltre, con ogni chiamata il compilatore dovrà generare un qualche tipo di una classe wrapper-implementazione (ancora una volta con il tema dello spazio dei nomi). Infine, se abbiamo due metodi diversi con lo stesso tipo strutturale che sono compilati separatamente, abbiamo appena esploso il numero di interfacce noi richiesti.

Non è che l'ostacolo non poteva essere superata, ma se si vuole avere la digitazione strutturale con accesso "diretto" per particolari tipi del modello tipo caratteristica sembra essere la soluzione migliore di oggi.

Altri suggerimenti

Se non ricordo male da una discussione sul Scala-Inernals mailing list, il problema con questo è identità di un oggetto, che si conserva dal approccio attuale alla compilazione, si perde quando si avvolgono i valori.

Pensateci. Considerare Classe A

class A { def a1(i: Int): String = { ... }; def a2(s: String): Boolean = { ... }

Alcuni posto nel programma, possibilmente in una libreria compilata separatamente, viene utilizzato questo tipo strutturale:

{ def a1(i: Int): String }

e altrove, questo viene utilizzato:

{ def a2(s: String): Boolean }

Come, oltre a un'analisi globale, è di classe A per essere decorato con le interfacce necessarie per consentirgli di essere utilizzato in cui vengono specificati i tipi strutturali lontane?

Se ogni possibile tipo strutturale che una determinata classe potrebbe conformarsi viene utilizzato per generare un'interfaccia catturare quel tipo strutturale, c'è un'esplosione di tali interfacce. Ricordare, che un tipo strutturale può menzionare più di un membro richiesto, quindi per una classe di N elementi comuni (vals o defs) tutti i possibili sottoinsiemi di coloro N sono necessari, e questo è il powerset di N cui cardinalità è 2 ^ N.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top