Warum Kompilierung-generative Techniken zur Struktur Typisierung getrennte Sammlung verhindern?

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

  •  29-09-2019
  •  | 
  •  

Frage

Ich las (ok, Skimming) Dubochet und Odersky compilieren Konstruktionstypen auf die JVM und wurde nach dem folgenden Anspruch verwirrt:

Generative Techniken erstellen Java-Schnittstellen stehen in für Strukturtypen auf der JVM. Die Komplexität solcher Techniken liegt darin, dass alle Klassen, die verwendet werden sollen als Strukturtypen überall im Programm implementieren muss die richtigen Schnittstellen. Wenn diese zum Zeitpunkt der Kompilierung durchgeführt, es verhindert getrennte Sammlung.

(Hervorhebung hinzugefügt)

Sie sich das Autoclose Beispiel aus dem Papier:

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

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

Könnten wir nicht eine Schnittstelle für den Closeable Typ erzeugen wie folgt:

public interface AnonymousInterface1 {
   public void close();
}

und verwandelt unsere Definition von autoclose zu

// 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 }
}

Dann einen Anruf Ort für autoclose betrachten:

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

Da fis ein FileInputStream ist, die nicht AnonymousInterface1 nicht implementieren, müssen wir einen Wrapper generieren:

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

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

Ich muss fehlen, etwas , aber es ist mir unklar, was es ist. Warum sollte dieser Ansatz verhindert getrennte Sammlung?

War es hilfreich?

Lösung

Ich benutze den impliziten Ansatz (mit typeclasses) Sie beschreiben in der Scala ARM-Bibliothek . Denken Sie daran, dass dies eine Hand codierte Lösung für das Problem.

Das größte Problem hier ist implizite Auflösung. Der Compiler wird nicht Wrapper on the fly für Sie generieren, müssen Sie dies vor der Zeit tun und stellen Sie sicher, sie sind eine der implizite Umfang. Diese Mittel (für Scala-ARM), dass wir „gemeinsam“ Wrapper für was auch immer Ressourcen bieten wir können, und fallen zurück auf Reflexion basierende Typen, wenn wir nicht die entsprechenden Wrapper finden. Dies ergibt den Vorteil, dass der Benutzer zu ermöglichen, ihre eigenen Wrapper mit normalen impliziten Regeln angeben.

Siehe auch: Die Ressourcentyp-Eigenschaft und alle seine vordefinierte Wrapper.

Auch gebloggt ich über diese Technik beschreibt die implizite Auflösung Magie im Detail: Monkey Patching, Duck Typing und Typklassen .

In jedem Fall werden Sie wahrscheinlich nicht wollen, zu hand kodieren eine Typklasse jedes Mal wenn Sie Strukturtypen verwenden. Wenn Sie tatsächlich die Compiler automatisch eine Schnittstelle zu erstellen und zu tun, die Magie für Sie wollen, könnte es chaotisch. Jedesmal, wenn man einen Strukturtyp definiert, wird der Compiler eine Schnittstelle für sie schaffen (irgendwo im Äther vielleicht?). Wir müssen jetzt Namespaces für diese Dinge hinzuzufügen. Auch bei jedem Aufruf wird der Compiler muss irgendeine Art von Wrapper-Implementierungsklasse erzeugt (wieder mit der Namensraum Ausgabe). Schließlich, wenn wir zwei verschiedene Methoden mit dem gleichen Strukturtyp aufweisen, die separat kompiliert werden, haben wir explodierte nur die Zahl der Schnittstellen benötigen wir.

Nicht, dass die Hürde nicht überwunden werden kann, aber wenn Sie wollen strukturelle Typisierung haben, mit „direktem“ Zugang für bestimmte Typen des Typ-Trait-Muster scheint die beste Wahl für heute zu sein.

scroll top