【问题标题】:Static return type of Scala macrosScala 宏的静态返回类型
【发布时间】:2012-11-20 03:14:35
【问题描述】:

所以我有这个宏:

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 = Bar@4118f8dd

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

其次,这种行为是否在某处指定?这似乎是一组相当基本的问题,但我无法搜索到明确的解释或讨论。

【问题讨论】:

  • @som-snytt:但我仍然希望foo 上的返回类型拥有最终决定权(尽管我也很高兴它没有)。
  • FooExample.foo 上的返回类型注释在这里非常奇怪。这就是我期望宏的行为方式。
  • @som-snytt 你能详细说明一下吗?宏应该能够与谁通信?

标签: scala types macros scala-2.10 scala-macros


【解决方案1】:

这种行为没有明确说明,但它是有意的,尽管它可能看起来令人困惑。我们计划详细说明返回类型在宏签名中的作用,但目前我觉得拥有灵活性是件好事。

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

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

【讨论】:

  • 这是否意味着不能在隐式搜索中使用实际展开的类型,除非该搜索由宏本身显式完成?
  • 现在不可能,以后可能也不可能。否则隐式搜索将不得不急切地扩展范围内的所有隐式宏。你有一个特定的用例吗?
  • 不,我只是想在脑海中勾勒出事物的运作方式;我认为 c.inferImplicitValue 在大多数情况下都可以解决问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-02
  • 2021-07-26
  • 2022-11-15
  • 1970-01-01
  • 1970-01-01
  • 2015-03-09
  • 1970-01-01
相关资源
最近更新 更多