3

Dubochet and Odersky's Compiling Structural Types on the JVMを読んでいて (わかりました、スキミング)、次の主張に混乱しました。

ジェネレーティブ手法は、JVM 上の構造型に代わる Java インターフェースを作成します。このような手法の複雑さは、プログラム内の任意の場所で構造型として使用されるすべてのクラスが適切なインターフェイスを実装する必要があることにあります。これがコンパイル時に行われると、個別のコンパイルが妨げられます。

(強調追加)

論文の autoclose の例を考えてみましょう:

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

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

次のような型のインターフェイスを生成できませんでしたCloseable:

public interface AnonymousInterface1 {
   public void close();
}

の定義autoclose

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

次に、 の呼び出しサイトを検討しますautoclose

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

fisFileInputStreamを実装していないため、AnonymousInterface1ラッパーを生成する必要があります。

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

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

何かが欠けているに違いありませんが、それが何であるかは不明です。このアプローチが個別のコンパイルを妨げるのはなぜですか?

4

3 に答える 3

7

Scala-Inernalsメーリング リストでの議論から思い出したように、これに関する問題は、現在のコンパイル方法では保持されているオブジェクト ID が、値をラップすると失われることです。

于 2010-08-17T03:37:07.230 に答える
4

考えてみてください。クラスAを考える

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

プログラムのどこかで、おそらく個別にコンパイルされたライブラリで、この構造型が使用されます。

{ def a1(i: Int): String }

他の場所では、これが使用されます。

{ def a2(s: String): Boolean }

グローバルな分析とは別に、クラス A は、それらの広範囲にわたる構造型が指定されている場所で使用できるようにするために必要なインターフェイスでどのように装飾されるのでしょうか?

特定のクラスが準拠できる可能性のあるすべての構造型を使用して、その構造型をキャプチャするインターフェイスを生成すると、そのようなインターフェイスが急増します。構造型は複数の必要なメンバーに言及している可能性があるため、N 個のパブリック要素 (val または def) を持つクラスでは、これらの N のすべての可能なサブセットが必要であり、それがカーディナリティが 2^N である N の累乗セットであることに注意してください。

于 2010-08-17T16:17:08.613 に答える
1

私は実際に、 Scala ARMライブラリで説明している暗黙のアプローチ(型クラスを使用)を使用しています。これは問題に対する手書きの解決策であることを忘れないでください。

ここでの最大の問題は暗黙の解決です。コンパイラーはその場でラッパーを生成しません。事前にラッパーを生成し、それらが暗黙のスコープの1つであることを確認する必要があります。これは、(Scala-ARMの場合)可能な限りのリソースに「共通」ラッパーを提供し、適切なラッパーが見つからない場合はリフレクションベースのタイプにフォールバックすることを意味します。これにより、ユーザーが通常の暗黙のルールを使用して独自のラッパーを指定できるという利点があります。

参照: リソースタイプ-特性とそのすべての事前定義されたラッパー。

また、暗黙の解決の魔法について詳しく説明しているこの手法についてブログを書きました:モンキーパッチ、ダックタイピング、型クラス

いずれにせよ、構造型を使用するたびに型クラスを手動でエンコードすることはおそらく望ましくありません。実際にコンパイラーにインターフェースを自動的に作成させて魔法をかけてもらいたい場合は、面倒になる可能性があります。構造型を定義するたびに、コンパイラーはそのためのインターフェースを作成する必要があります(おそらくエーテルのどこかに?)。次に、これらの名前空間を追加する必要があります。また、呼び出しのたびに、コンパイラーはある種のラッパー実装クラスを生成する必要があります(これも名前空間の問題があります)。最後に、別々にコンパイルされた同じ構造型の2つの異なるメソッドがある場合、必要なインターフェースの数を増やしました。

ハードルを克服できなかったわけではありませんが、特定の型に「直接」アクセスできる構造型を使用したい場合は、型特性パターンが今日の最善の策のようです。

于 2010-08-29T00:39:20.530 に答える