前段时间有个叫 Nim (又名 Nimrod)的语言莫名其妙火了——好像最初是因为 有个给 Rust 写书的家伙扬言要“放弃 Rust 投奔 Nim”,然后大家就纷纷好奇 这个叫 Nim 的语言是何方神圣……
我嘛自然也不能免俗,试着用 Nim 写了一个 web 服务器——叫做 Nyx ,有兴趣 的同学可以到 Github 上 围观——结果却不尽如人意。
Nim 简介
熟悉 Cython 的同学,基本上可以认为 Nim 和 Cython 是一样类型的东西。 Nim 是一种静态类型、自带内存管理、编译执行的语言。
- 静态类型: Nim 在声明变量的时候必须(显式或隐式地)声明其类型;不 过由于 Nim 支持类型推断,所以实际程序中需要显式声明类型的地方其实 不多;
- 内存管理: Nim 使用 基于引用计数的垃圾回收算法 ,而且只在进行 内存分配的时候触发;我没有深入调查其性能,也不清楚它在多线程环境 下的表现,至少在我的单线程服务器上没什么问题;
- 编译执行: Nim 编译器会先将程序编译为中间语言(支持 C 、 C++ 、 Objective-C 甚至是 Javascript ),然后调用中间语言的原生编译器/解 析器;不过从 Nim 标准库的代码来看,被支持得最好的还是 C 语言。
Nim 的亮点
除了以上性质以外, Nim 还是很有特点的。以下是我认为是亮点的特性(排 名分先后):
- 对 宏 的支持。 Nim 支持类似 Lisp 的宏,基本上可以在编译代码前 任意操作语法树,而且在我看来它的简化版 template 已经够简洁了, 很有 Lisp 的神韵; Nim 的宏非常强大,以致有些关键语言特性甚至可 以在标准库里用宏实现,而不是写到编译器中——至于这样做是不是好事, 就见仁见智了……
- 静态类型和类型推断系统很严格,而且整合得非常好,可以用 distinct 关键字进行更精细、更安全的类型定义,并提供类似 C++ 模板的 generics 用以提取独立于特定类型的代码。
- 尽量减小副作用的影响。这其实涉及几个 Nim 语言的小特性:函数形参 默认是不能重新赋值的;模块中的函数和对象属性默认是不导出的(类似 private 成员);有专门的 Effect System 用以跟踪函数的副作用; 等等。
- 与 Go 语言类似,对象(这里指 object 类型)定义和方法定义是完全 分离的,所以对对象方法的扩展很方便。
- 使用缩进标示代码块。
Nim 的缺点
列了这么些优点,接下来自然是要黑一下了……这些是我在写服务器的时候遇 到的问题,按蛋疼程度排序:
- 标准库缺少测试。 Nim 源码里的测试基本上是针对编译器的,而标准库 的测试覆盖率就基本上取决于有多少人用过相应的模块……像我在写服务器 时用得比较多的 asyncdispatch 和 asyncfile 模块,就存在一系列低级 但是致命的错误,一看就知道根本没人认真的用过这些API.
- Nim 的文档里将它的面向对象要素介绍为 “minimalistic”,但是也太简 单了,甚至不能自动调用构造函数,这在继承链很长的时候会显得很麻 烦而且容易出错;另外对象不支持异步方法,想要异步方法的话只能自己 手工打造一个虚函数表(见 Nyx 源码中的 io 模块)
- Nim 程序中的 pragma 承担了太多功能。基本上编译器作者们觉得放不 进语法里的特性都被仍到 pragma 里去了,但是实际上有些特性使用起来 还挺频繁的,这导致 Nim 程序中 pragma 出镜次数非常多,而且重要的 标示还容易混在 deprecated 之类的注释性 pragma 中被人眼忽略掉。
很明显缺点 1 的成因是 Nim 还不普及,用户基数小,但是 2 和 3 是开发 者作出的选择,短期内怕是不会有所改变了。
Nyx 的状态
在给 Nim 的 asyncdispatch 模块打了 patch 之后, Nyx 是能正常工作的, 但也仅限如此了。
除此之外 asyncdispatch 模块 async 宏的实现有个蛋疼的 bug : await 语句后面不能接对象成员的引用(见 Nyx 源码 demo/filehub.nim 中的 waitForTransfer 函数)。
另外,不知道 Nim 的原作者 Araq 和 unittest 模块的作者有什么过节, 反正 Araq 非常讨厌 unittest 模块,但是却没有替代方案……在 Nim 的论坛 上问“测试用什么框架好”,最常得到的答复竟然是“自己写”……所以 Nyx 的测 试是用几个简陋的宏拼凑出来的 ╮( ̄. ̄)╭ . 而 unittest 模块,现在貌似 是没人维护的状态……
所以,现在 Nim 的状态是,想要用它写点什么的话,就免不了要发现几个 bug 或者给上游贡献点代码;所以, Nyx 的状态也差不多这样,而且我大概 最近也不会去更新它的了……