带有类型属性的脏模板

时间:2017-08-05 00:31:30

标签: nim

我已经玩了一段时间的nim,而且经常让我感到困惑的是模板。我希望他们 - 至少在签名级别 - 像procs一样工作,但是他们会错过某些功能(比如可选/默认参数 - 昨天它真的把我扔了一个曲线球)

无论如何,我认为使用模板的模式很简单,所以这里有一些代码:

result
#  Name   PID Type HomeBrand HomeModel AutoBrand AutoModel
#1  11C AD15E Home         A      A152         B      K235
#2  12C AA05D Home         C       W54         H        H2
#3  20D  Z48J Home         I       A57         D     Y0878

编译正确,工作正常。由于我的模板很脏,因此template Kitten*(name: string, age, body: untyped) {.dirty.} = var kitty_name = name # my {.dirty.} exposes this echo("Hi, " & name) if age != 0: echo("wow, " & $age & " years old already!") body echo("Bye, " & name) template Kitten*(name: string, body: untyped) {.dirty.} = Kitten(name, 0, body) Kitten("Jimmy"): echo("It's really nice to meet you, " & kitty_name) ## Ralph and Jimmy cannot co-exist - it's fine, I understand the issue here # Kitten("Ralph", 5): # echo("Great that you joined us, " & kitty_name) 内可以使用kitty_name。取消评论拉尔夫并评论吉米,这也正常。

然后,我意识到body没有关联的类型。我当然不想要那个 - 我多么愚蠢!所以我解决了这个问题:

age

突然间,吉米没有编译。 Ralph很好--Ralph直接使用模板,但是因为Jimmy使用被覆盖的(如果该术语甚至适用于模板?)方法,突然它就像主要的Kitten关闭了它的边界一样?它不够脏吗?

所以问题是,它为什么有效,它为什么失败,是一个错误或误解的功能?或者我只是滥用模板?

(p.s。在0.17.0和最新的devel分支上试过这个)

2 个答案:

答案 0 :(得分:2)

因此,事实证明它不是一个错误。

将其添加到问题跟踪器,并收到Andreas本人的以下回复:

  

模板的过载需要就无类型参数的位置达成一致。这在手册中有记录。

(我发现的最近的手动条目是nim manual's "Lazy type resolution for untyped" section,我读的越多,我认为它就越少!)

仍然试图绕过这个;我已经尝试了一些简单的例子,我不认为这是整个解释 - 除非结论是"因此混合无类型和类型会导致未定义的行为 - 包括丢弃肮脏的pragma"这并不能让我满怀信心。

有一天,我会深入研究这个代码并更好地解释它。目前,这是一个悬而未决的问题。

答案 1 :(得分:2)

我认为这是一个可以解决的编译器错误,但我会提供当前行为的解释。

这里的关键是在Kitten的调用站点,涉及注入的kitty_name变量的块不能被类型检查(由于对不存在的变量的引用)。它们必须作为原始AST传递,这通过使用模板的untyped参数来指示。一旦引入另一个在同一位置不使用untyped参数的重载,编译器将尝试在重载解析期间键入检查传入的块,并且您将在调用站点处收到错误(不是在模板扩展后,因为你似乎在假设)。

编译器可能已经使用了几个额外的标准来避免错误 - 例如,它可以根据参数的数量排除其中一个重载。这就是我认为这个问题将来可以解决的原因。

要解决此问题,您可以重命名这两个模板,这样它们就不会重载:

template AgedKitten*(name: string, age: int, body: untyped) {.dirty.} =
  block:
    var kitty_name = name  # my {.dirty.} exposes this
    echo("Hi, " & name)
    if age != 0: echo("wow, " & $age & " years old already!")
    body
    echo("Bye, " & name)

template Kitten*(name: string, body: untyped) {.dirty.} =
  AgedKitten(name, 0, body)

Kitten("Jimmy"):
  echo("It's really nice to meet you, " & kitty_name)

AgedKitten("Ralph", 5):
  echo("Great that you joined us, " & kitty_name)

过去,我还对typed和unyped参数之间的区别提供了更深入的解释,您也可以找到它们:

typed vs untyped vs expr vs stmt in templates and macros