Прокси / делегаты в 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). Итак, мои вопросы
- продолжается ли работа над плагином AutoProxy?
- это найдет свой путь в компилятор?
- другие рассматриваются подходы?
- наконец, указывает ли это на значительную слабость в Scala? В конце концов, разве нельзя определить a
Proxy
черта данного макросы в стиле lisp?
2 ответов
четыре вопроса, четыре ответа
Я, хотя семья должна быть на первом! Плюс другие участвуют в рассмотрении общей проблемы с синтезированием методов в плагине компилятора.
если да, то, скорее всего, это будет в другой форме, возможно, без использования аннотаций.
Я не знаю никаких эквивалентных плагинов, хотя один из проектов-кандидатов Scala GSOC был частично основан на моем коде autoproxy. Однако есть одно очень чистое решение, которое будет работать в большинстве случаев и вообще не нуждается в плагине компилятора: вы определяете неявное преобразование из FooProxy в Foo, которое просто возвращает
self
член; это приведет вас большую часть пути туда. Основные проблемы с подходом заключаются в том, что это усложнит жизнь, если вам нужно использовать свой код с Java, он может быть менее эффективным с точки зрения скорости/памяти, и это еще один imlicit, который вы должны знать из.расстраивает то, что почти вся необходимая логика уже доступна в компиляторе, и она используется для 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)
}
проект находится на очень ранней стадии доказательства концепции на момент написания этой статьи, поэтому осторожность оправдана.