Прокси/делегаты в 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 прокси-характеристик будут намного меньше). Конечно, я нашел плагин Kevin Wright AutoProxy. Плагин предназначен для решения проблемы с прокси-сервером, а также с другими вариантами использования (включая динамические микшины):
class FooProxy(@proxy val self: Foo) { ... }
К сожалению, похоже, что работа над ним застопорилась в ноябре (2009). Итак, мои вопросы:
- Продолжается ли работа над плагином AutoProxy?
- Может ли это найти его в компиляторе?
- Рассматриваются ли какие-либо другие подходы?
- Наконец, указывает ли это на значительную слабость в Scala? В конце концов, не удалось бы определить черту
Proxy
с заданными макросами lisp?
Ответы
Ответ 1
Четыре вопроса, четыре ответа
-
Я, хотя семья должна быть первой! Кроме того, другие участвуют в рассмотрении общей проблемы с методами синтеза в плагине компилятора.
-
Если это так, это, скорее всего, будет в другой форме, возможно, без использования аннотаций.
-
Я не знаю каких-либо эквивалентных плагинов, хотя один из проектов-кандидатов на Scala GSOC был частично основан на моем автопрокси-коде. Существует, однако, одно очень чистое решение, которое будет работать в большинстве случаев и вообще не нуждается в компиляторе: вы определяете неявное преобразование из FooProxy в Foo, которое просто возвращает член self
; это даст вам большую часть пути. Основные проблемы, связанные с этим подходом, состоят в том, что это сделает жизнь сложнее, если вам нужно использовать свой код на Java, он может быть менее эффективным с точки зрения скорости/памяти, а другой - имплицитом, о котором вы должны знать.
-
Отвратительная часть состоит в том, что почти вся необходимая логика уже доступна в компиляторе, и она используется для mixins, поэтому действительно должен быть элегантный способ обработки задачи.
Ответ 2
Адам Варски недавно опубликовал блог о Макро-ориентированный подход, который может работать в 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)
}
Проект находится на очень раннем этапе доказывания концепции на момент написания этой статьи, поэтому предостережение оправданно.