【发布时间】:2011-03-29 05:58:04
【问题描述】:
我最近看到了几个需要使用代理的 Scala 问题(例如 here、here 和 here),并且在我自己的工作中不止一次出现过。 Scala 库有许多代理特征(如果我没记错的话,有 14 个)。
代理类/特征通常包含很多样板:
class FooProxy(val self: Foo) extends Foo {
// added behavior
def mymethod = ...
// forwarding methods
def method1 = self.method1
def method2(arg: String) = self.method2(arg)
...
}
trait Foo {
def method1: Unit
def method2(arg: String): Unit
}
我的第一个想法是定义一个Proxy[T] trait,可以如下使用:
class FooProxy(val self: Foo) extends Proxy[Foo] {
// added behavior
def mymethod = ...
}
在哪里trait Proxy[T] extends T。当然,实际上不可能在没有编译器魔法的情况下定义 Proxy 特征。
我的下一个想法是寻找一个编译器插件(这样的功能显然不在现有的编译器中,或者这 14 个代理特征的来源会小得多)。果然,我找到了Kevin Wright's AutoProxy plugin。该插件旨在巧妙地解决代理问题,以及其他用例(包括动态混合):
class FooProxy(@proxy val self: Foo) { ... }
不幸的是,它的工作似乎在 11 月(2009 年)停滞不前。所以,我的问题是
- 是否有关于 AutoProxy 插件的继续工作?
- 这会进入编译器吗?
- 是否正在考虑其他方法?
- 最后,这是否表明 Scala 存在显着的弱点?毕竟,给定 lisp 风格的宏难道不能定义
Proxy特征吗?
【问题讨论】:
-
特征不能有参数。您是否建议添加它们?此外,您还没有展示任何无法通过添加隐式转换来修复的内容。创建隐式转换的提议是不必要的样板吗?
-
“特征不能有参数”:愚蠢的错误,已修复。
-
隐式转换解决了类似的问题,但它们并不总是合适的(否则为什么 EPFL 的家伙会在 Scala 库中包含这么多代理?)。一方面,它们比委派产生更多的开销。其次,大量使用隐式转换会损害可维护性/可读性。
-
最后,除非有人能想到一个聪明的解决方法,否则这可能是杀手锏,隐式转换不会保留修改后的行为。也就是说,如果代理覆盖了某个方法,则该覆盖在转换时会丢失。因此,如果我将
FooProxy放入List[Foo],它的酷炫装饰就会突然消失。