Scala中的代理/代理

Aar*_*rup 18 lisp delegates scala scala-2.8

我最近看到了几个Scala问题(例如这里,这里这里),它们要求使用代理,并且它在我自己的工作中不止一次出现.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
}
Run Code Online (Sandbox Code Playgroud)

我的第一个想法是定义一个Proxy[T]可以如下使用的特征:

class FooProxy(val self: Foo) extends Proxy[Foo] {
   // added behavior
   def mymethod = ...
}
Run Code Online (Sandbox Code Playgroud)

哪里trait Proxy[T] extends T.当然,如果Proxy没有编译器魔法,实际上不可能定义特征.

我的下一个想法是寻找一个编译器插件(这种功能显然不在现有的编译器中,或者这14个代理特性的来源会小得多).果然,我找到了Kevin Wright的AutoProxy插件.该插件旨在整齐地解决代理问题,以及其他用例(包括动态混合):

class FooProxy(@proxy val self: Foo) { ... }
Run Code Online (Sandbox Code Playgroud)

不幸的是,它的工作似乎在11月(2009年)停滞不前.所以,我的问题是

  1. AutoProxy插件是否还在继续?
  2. 这会进入编译器吗?
  3. 是否正在考虑其他方法?
  4. 最后,这是否表明Scala存在重大缺陷?毕竟,Proxy给定lisp风格的宏是不是可以定义特征?

Kev*_*ght 8

四个问题,四个答案

  1. 我是,虽然家人必须先来!还有其他人参与了在编译器插件中合成方法的一般问题.

  2. 如果是这样,它很可能是以不同的形式,也许不使用注释.

  3. 我不知道任何等效的插件,虽然Scala GSOC候选项目之一部分基于我的autoproxy代码.但是,有一个非常干净的解决方案在大多数情况下都可以工作,并且根本不需要编译器插件:您可以定义从FooProxy到Foo的隐式转换,它只返回self成员; 这将使你在那里大部分时间.这种方法的主要问题是,如果你需要使用Java中的代码,它会使生活变得更加困难,它在速度/内存方面可能效率较低,而且你需要注意的是另一个非常明显的问题.

  4. 令人沮丧的是,几乎所有必要的逻辑都已在编译器中可用,并且它用于mixins,因此确实应该有一种处理任务的优雅方式.


Aar*_*rup 6

Adam Warski 最近发表了一篇关于基于宏的方法的博客,该方法可能适用于Scala 2.11,并且肯定适用于Scala 2.10中的Macro Paradise编译器插件.

这个库可以让你写

class FooProxy(@delegate wrapped: Foo) extends Foo {
    // added behavior
    def mymethod = ...

    // forwarding methods (generated for you)
    // def method1 = wrapped.method1
    // def method2(arg: String) = wrapped.method2(arg)
}
Run Code Online (Sandbox Code Playgroud)

在撰写本文时,该项目处于一个非常早期的概念验证阶段,因此需要谨慎.