Прокси / делегаты в Scala

недавно я видел несколько вопросов 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
}

моей первой мыслью было определить Proxy[T] черта, которая может использоваться как следует:

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

здесь trait Proxy[T] extends T. Конечно, на самом деле невозможно определить Proxy черта без магии компилятора.

моей следующей мыслью было найти плагин компилятора (такой возможности явно нет в существующем компиляторе, или источники для этих 14 прокси-признаков были бы намного меньше). Конечно, я нашел плагин AutoProxy Кевина Райта. Плагин предназначен для решения проблемы прокси аккуратно, наряду с другими случаями использования (включая динамические миксины):

class FooProxy(@proxy val self: Foo) { ... }

к сожалению, похоже, что работа над ним застопорилась в ноябре (2009). Итак, мои вопросы

  1. продолжается ли работа над плагином AutoProxy?
  2. это найдет свой путь в компилятор?
  3. другие рассматриваются подходы?
  4. наконец, указывает ли это на значительную слабость в Scala? В конце концов, разве нельзя определить a Proxy черта данного макросы в стиле lisp?

2 ответов


четыре вопроса, четыре ответа

  1. Я, хотя семья должна быть на первом! Плюс другие участвуют в рассмотрении общей проблемы с синтезированием методов в плагине компилятора.

  2. если да, то, скорее всего, это будет в другой форме, возможно, без использования аннотаций.

  3. Я не знаю никаких эквивалентных плагинов, хотя один из проектов-кандидатов Scala GSOC был частично основан на моем коде autoproxy. Однако есть одно очень чистое решение, которое будет работать в большинстве случаев и вообще не нуждается в плагине компилятора: вы определяете неявное преобразование из FooProxy в Foo, которое просто возвращает self член; это приведет вас большую часть пути туда. Основные проблемы с подходом заключаются в том, что это усложнит жизнь, если вам нужно использовать свой код с Java, он может быть менее эффективным с точки зрения скорости/памяти, и это еще один imlicit, который вы должны знать из.

  4. расстраивает то, что почти вся необходимая логика уже доступна в компиляторе, и она используется для mixins, так что действительно должны быть элегантный способ обработки задачи.


Адам Варской недавно в блоге о подход на основе макросов это может работать в Scala 2.11 и определенно работает с плагином компилятора Macro Paradise в Scala 2.10.

эта библиотека позволит вам написать

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

проект находится на очень ранней стадии доказательства концепции на момент написания этой статьи, поэтому осторожность оправдана.