2012-12-02 135 views
38

所以我有这个宏:静态返回类型宏

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,当我拨打foo时,仍然会获得静态类型Bar

其次,这种行为在某处指定了吗?这似乎是一个相当初级的问题,但我一直无法找到明确的解释或讨论。

+2

@ som-snytt:但我仍然会预期'foo'上的返回类型有最后一个字(尽管我也很高兴它没有)。 –

+2

'FooExample.foo'上的返回类型注释在这里非常奇怪。否则,我会期待宏的行为。 – drstevens

+0

@drstevens:同意。 –

回答

19

此行为未指定,但有意,尽管它可能会出现混淆。我们打算详细说明返回类型在宏特征中的作用,但目前我觉得灵活性是一件好事。

也有时行为不一致,例如,当宏在类型推断中被捕获时,将使用它的静态签名(例如在你的示例中为Foo),而不是实际扩展的类型。这是因为宏扩展是故意延迟的,直到类型推断完成(所以宏实现可以看到推断类型,而不是类型变量)。这是一种权衡,不一定是最好的,所以我们打算很快重新审视它:https://issues.scala-lang.org/browse/SI-6755

这个部门的另一个问题是隐含的宏。当隐式宏的返回类型是通用的并且需要从所请求的隐式值类型中推断时,会发生不好的事情。这使得目前不可能使用宏来生成类型标签:https://issues.scala-lang.org/browse/SI-5923

+0

这是否意味着不可能在隐式搜索中使用实际扩展的类型,除非该搜索是由宏本身明确完成的? –

+1

现在不可能,以后可能不可能。否则,隐式搜索将不得不急切地扩展范围内的所有隐式宏。你有没有特别的用例? –

+0

不,我只是想形成一个关于事情如何工作的心理图景;我想,在大多数情况下,c.inferImplicitValue将会诀窍。 –