Итак, у меня есть этот макрос:
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
.
Во-вторых, такое поведение указано где-то? Это похоже на довольно элементарный набор проблем, но я не смог найти четкое объяснение или обсуждение.