Итак, у меня есть этот макрос:
import language.experimental.macros
import scala.reflect.macros.Context
class Foo
class Bar extends Foo { def launchMissiles = "launching" }
object FooExample {
def foo: Foo = macro foo_impl
def foo_impl(c: Context): c.Expr[Foo] =
c.Expr[Foo](c.universe.reify(new Bar).tree)
}
Я сказал три раза, что хочу foo вернуть foo, и все же я могу сделать следующее (в 2.10.0-RC3):
scala> FooExample.foo
res0: Bar = [email protected]
scala> res0.launchMissiles
res1: String = launching
То же самое происходит, если я удаляю параметры типа на c.Expr. Если я действительно хочу удостовериться, что тот, кто называет foo, не может видеть, что они получают Bar, мне нужно добавить типу типа в самом дереве.
Это на самом деле довольно хорошо - это означает, например, что я могу указать макрос в какой-либо схеме и создать анонимный подкласс некоторого класса Vocabulary с помощью методов-членов, представляющих термины в словаре, и они будут доступны на возвращаемом объекте.
Я хотел бы точно понять, что я делаю, поэтому у меня есть несколько вопросов. Во-первых, каков тип возврата для метода foo на самом деле? Доступно ли это для (необязательной) документации? Он явно ограничивает тип возврата (например, я не могу изменить его на Int в этом случае), и если я полностью его удалю, то получаю следующее:
scala> FooExample.foo
<console>:8: error: type mismatch;
found : Bar
required: Nothing
FooExample.foo
^
Но я могу изменить его на Any и все равно получить статически типизированный Bar при вызове foo.
Во-вторых, такое поведение указано где-то? Это похоже на довольно элементарный набор проблем, но я не смог найти четкое объяснение или обсуждение.