为什么用于结构键入的编译时间生成技术可以防止单独编译?
-
29-09-2019 - |
题
我正在阅读(好的,略读)Dubochet和Odersky的 在JVM上编译结构类型 并对以下主张感到困惑:
生成技术创建了Java接口,可以在JVM上使用结构类型。此类技术的复杂性在于,所有要用作程序中的结构类型的类都必须实现正确的接口。 当在编译时完成此操作时,它会防止各自的汇编。
(添加了强调)
考虑本文中的自相传器示例:
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) { ... }
自从 fis
是一个 FileInputStream
, ,不实施 AnonymousInterface1
, ,我们需要生成一个包装器:
class FileInputStreamAnonymousInterface1Proxy(val self: FileInputStream)
extends AnonymousInterface1 {
def close() = self.close();
}
object FileInputStreamAnonymousInterface1Proxy {
implicit def fis2proxy(fis: FileInputStream): FileInputStreamAnonymousInterface1Proxy =
new FileInputStreamAnonymousInterface1Proxy(fis)
}
我一定失踪了 某物, ,但这对我来说还不清楚。为什么这种方法会阻止单独的汇编?
解决方案
我实际上使用了您在 Scala Arm库. 。请记住,这是解决问题的手工编码解决方案。
这里最大的问题是隐性解决方案。编译器不会为您生成包装器,您必须提前这样做,并确保它们是隐性范围之一。这意味着(对于Scala-Arm),我们为我们提供的任何资源提供了“常见”包装,并且在找不到合适的包装器时,它可以回到基于反射的类型中。这具有允许用户使用普通隐式规则指定自己的包装器的优势。
看: 资源类型特征 所有这些都是预定义的包装器。
另外,我在博客上介绍了这种技术,描述了隐性分辨率的魔法: 猴子补丁,鸭打字和类型类.
无论如何,您可能不想每次使用结构类型时都要手工编码类型类。如果您实际上希望编译器自动创建一个界面并为您做魔术,则可能会变得凌乱。每次定义结构类型时,编译器都必须为其创建一个接口(也许在以太中的某个地方?)。现在,我们需要为这些东西添加名称空间。另外,每次呼叫,编译器都必须生成某种包装器实施类(再次带有名称空间问题)。最后,如果我们有两种不同的方法,它们分别编译了相同的结构类型,我们刚刚爆炸了所需的接口数。
并不是说无法克服障碍,但是如果您想对特定类型的“直接访问”进行结构性打字,那么Type-Tech模式似乎是您今天最好的选择。
其他提示
我记得 讨论 在 Scala Inners 邮寄列表,当您包装值时,邮件列表是对象身份,该对象身份被当前的编译方法保留。
考虑一下。考虑A类
class A { def a1(i: Int): String = { ... }; def a2(s: String): Boolean = { ... }
该程序中的某些位置可能在单独编译的库中,使用了这种结构类型:
{ def a1(i: Int): String }
在其他地方,使用了这一点:
{ def a2(s: String): Boolean }
除了全球分析外,A类别A类如何用所需的接口进行装饰,以便在指定这些遥远的结构类型的情况下使用它?
如果给定类可以符合的每种可能的结构类型都用于生成一个接口捕获该结构类型,则会发生这种接口的爆炸。请记住,结构性类型可能会提及多个必不可少的成员,因此对于具有n个公共元素(vals或defs)的类,所有可能的n可能子集都是必需的,这就是N的基数为2^n的N的功能。