【问题标题】:typed vs untyped vs expr vs stmt in templates and macros模板和宏中的类型化 vs 非类型化 vs expr vs stmt
【发布时间】:2015-09-30 18:28:24
【问题描述】:

我最近一直在使用模板和宏,但我不得不说我几乎没有找到关于这些重要类型的信息。这是我肤浅的理解:

  • typed/expr 是以前必须存在的东西,但您可以使用 .immediate。克服它们。
  • untyped/stmt 是之前没有定义的东西/一个或多个语句。

这是一个非常模糊的类型概念。我想对它们有更好的解释,包括哪些类型应该用作返回。

【问题讨论】:

    标签: templates macros nim-lang


    【解决方案1】:

    这些不同的参数类型的目标是在指定编译器应该接受什么作为宏的参数时为您提供更高级别的精度。

    让我们想象一个可以求解数学方程的假设宏。它将像这样使用:

    solve(x + 10 = 25) # figures out that the correct value for x is 15
    

    这里,宏只关心提供的 AST 树的结构。它不要求同一棵树是当前范围内的有效表达式(即定义 x 等等)。该宏只是利用了 Nim 解析器,该解析器已经可以解码大多数数学方程,将它们变成更容易处理的 AST 树。这就是untyped 参数的用途。它们没有经过语义检查,您得到的是原始 AST。

    精度阶梯的下一步是typed 参数。它们允许我们编写可以接受任何表达式的通用类型的宏,只要它在当前范围内具有适当的含义(即可以确定其类型)。除了更早地捕获错误之外,这还有一个好处是我们现在可以使用宏体内的表达式类型(使用macros.getType proc)。

    我们可以通过要求特定类型的表达式(具体类型或类型类/概念)来获得更精确的信息。宏现在将能够像常规 proc 一样参与重载决议。重要的是要理解宏仍然会接收 AST 树,因为它会接受可以在编译时计算的表达式和只能在运行时计算的表达式。

    最后,我们可以要求宏接收在编译时提供的特定类型的值。宏可以使用此值来参数化代码生成。这是static parameters 的领域。在宏体内,它们不再是 AST 树,而是普通的类型良好的值。

    到目前为止,我们只讨论了表达式,但 Nim 的宏也接受和生成块,这是我们可以控制的第二个轴。 expr 一般表示单个表达式,而stmt 表示表达式列表(历史上,它的名称来自 StatementList,在 Nim 中统一表达式和语句之前,它作为一个单独的概念存在)。

    用模板的返回类型最容易说明区别。考虑系统模块中的newException 模板:

    template newException*(exceptn: typedesc, message: string): expr =
      ## creates an exception object of type ``exceptn`` and sets its ``msg`` field
      ## to `message`. Returns the new exception object.
      var
        e: ref exceptn
      new(e)
      e.msg = message
      e
    

    即使认为构造异常需要几个步骤,通过指定expr 作为模板的返回类型,我们告诉编译器只有最后一个表达式将被视为模板的返回值。其余语句将被内联,但巧妙地对调用代码隐藏。

    作为另一个例子,让我们定义一个特殊的赋值运算符,它可以模拟 C/C++ 的语义,允许在 if 语句中进行赋值:

    template `:=` (a: untyped, b: typed): bool =
      var a = b
      a != nil
    
    if f := open("foo"):
      ...
    

    指定具体类型与使用expr 具有相同的语义。如果我们改用默认的 stmt 返回类型,编译器将不允许我们传递“表达式列表”,因为 if 语句显然需要一个表达式。

    .immediate. 是很久以前的遗留物,当时模板和宏不参与重载决议。当我们第一次让他们了解类型系统时,大量代码需要当前的 untyped 参数,但是重构编译器以从一开始就引入它们太难了,相反我们添加了 .immediate. pragma 作为一种方法强制整个宏/模板的向后兼容行为。

    使用typed/untyped,您可以更精细地控制宏的各个参数,.immediate. pragma 将逐渐被淘汰和弃用。

    【讨论】:

    • 很好的解释!谢谢你扎。
    猜你喜欢
    • 1970-01-01
    • 2013-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-18
    • 1970-01-01
    • 2020-12-10
    相关资源
    最近更新 更多