作者: ** 张宏波**, 前OCaml编译器核心作者,现BuckleScript作者。
近日,Bloomberg 宣布其开源的 JavaScript 编译器 BuckleScript 到达了1.0 版本, 作为其作者,我很高兴向大家分享它的意义和功能。
诱人的JS平台
Bloomberg 早在04年就开始在服务器端使用 JS 了,现在 JS 已经是其内部使用最多的程序语言之一,有着丰富的大规模开发部署 JS 的经验。而在开源世界,随着几大IT巨头对 JS 引擎和工具的大力投入,以及 NodeJS 的兴起,这几年,JS已经成为工业界炙手可热的程序语言。
�不难发现现在的软件行业——从互联网行业到传统软件领域—— JS�平台,
这个唯一的跨平台语言正在吞噬着越来越多的软件领域(因为移动的崛起Java 已经不再是一个跨平台语言了):
浏览器不再单单只是投放内容的一个平台,越来越多的应用程序开始通过浏览器直接部署,像BuckleScript playground这
样的整个工业级别的编译器可以流畅的直接跑在浏览器上,这在5年前甚至都是不可想象的。Google最近主推的Progressive Web APP 将会给浏览器带来更强大的API。而最新的Web Assembly 标准 将会使得 JavaScript 平台可以覆盖更多的领域:比如传统的数值计算领域。WASM 相当于给 JS 提供了一个接入原生平台的FFI, JS 作为这个平台的胶水语言毫无疑问有着最多的机会。
JS 平台已经不再局限于浏览器, 相反它已经开始反噬, 开始入侵其他领域。最有名的是服务器端NodeJS, 桌面端Electron, 物联网 IoT, 移动端React Native 等。
然而 JS 作为一个只花了两周时间开发的动态语言是很难承载大规模,高性能开发的。它最主要的痛点有两个:
程序没有类型 很难做维护和安全的重构
程序性能过于依赖JS引擎的优化,性能很难预测,而且因为不同引擎性能变化较大
工业界需要更快更好的JS编译器
虽然JS平台很诱人,但是“动态语言难于构建大型程序”基本上已经是业界共识,一旦程序规模上来,维护起来基本上就是噩梦,在原来的Hack上添加新的Hack, 没有人敢修改原来的代码。
在BuckleScript之前,业界比较成熟的具有工业强度的JS替代语言主要是微软的TypeScript,那么BuckleScript相比TypeScript主要有哪些优点呢?我们可以从以下几点来分析:
更多的平台拓展性
BuckleScript 不是一个新的语言,它是把一个已经存在将近30年的语言 OCaml 编译成可读的 JS 。而OCaml本身对很多平台存在原生的后端支持。像golang一样,OCaml可以编译出汇编代码到iOS、Android、Windows、Linux、MacOS。而TypeScript只有JavaScript 一个后端。
拥抱 JavaScript 并不代表我们就要抛弃原生平台,当我们需要更快更可靠的性能的时候,我们可以有更多的选择。比如,做工具链的时候, TypeScript 的编译器同样也是用 TypeScript 写得可以跑在浏览器里,也可以跑在node上,但是它跑在node上得时候就比BuckleScript编译成汇编跑慢不止一个数量级。更好的类型安全,更多的类型推断,更好的语言特性
TypeScript是一个JS的超集,它存在很多历史包袱。微软引入TypeScript更多的是作为一个工具来使用的比如IDE的代码补全,相对安全的代码重构。而这个类型的准确性从第一天开始就不是它的设计初衷,以至于Facebook自己设计了一个相对更准确地类型系统 Flow。 OCaml 的类型系统是已经被形式化的证明过正确的。也就是说从理论上 BuckleScript 能够保证一旦编译通过是不会有运行时候类型错误的,而TypeScript却做不到这点。
TypeScript的类型推断很弱,基本上所有参数都需要显示的标注类型。不光是这点,像对函数式编程的支持,高阶类型系统GADT的支持几乎是没有。而OCaml本身是一个比Elm,PureScript还要强大的多的语言,它自身有一个非常高阶的module system,是为数不多的对dependent type提供支持的语言,polymorphic variant。而且pattern match的编译器也是优化过的。程序优化,代码删除,闪电一样的编译速度
BuckleScript不只是一个编译器更是一个optimizing compiler: 它做过的优化有: Code motion,Purity analysis, Cross module inliner, Constant folding/propagation, Partial evaluation,Strength reduction, escape analysis。我们做的benchmark显示同样immutable data structure,比如facebook immutablejs,
BuckleScript的实现有时候要快两到三倍不止,生成的代码经过代码删除之后只有不到 1K字节。而相比之下TypeScript编译器并不会做任何优化工作。
由于OCaml可以编译到汇编和JS, 而本身的BuckleScriptl编译器也可以编译到JS 和汇编。用户可以感受�JS版本的编译速度,而汇编版本的编译器更是要快一个数量级 编译单个文件只需要十几毫秒。
总之,与现有的其他JavaScript转译器比较,BuckleScript 旨在提供更快的编译速度, 更好的运行速度,可读和�更少的代码输出,以及最重要的和JS的互操作性。
BuckleScript 现状以及未来 以及和Reason的整合
BuckleScript已经被一些公司所采用,并且反馈很好,例如,下面是Facebook的程序员的评论:
I'm on the Facebook Reason team, and we're using BuckleScript to
compile OCaml into the best compiler output I've ever seen. People
didn't recognize that my React components were generated, not hand-written.
�评论中提到的Reason是由Facebook原React团队开发的,它是为 OCaml 提供的 JavaScript 类前端语法, 相当于给 OCaml 换了个壳,类似于 CoffeScript 对于 JS。
要强调的是, Reason 团队不仅仅在改进OCaml的语法,同时也在努力改善OCaml中的工具链,像构建系统、IDE等。我们之间有非常紧密的合作关系,BuckleScript外部函数接口的设计以及和JS的互操作得到了Reason团队很多反馈,希望将来能推出下一个版本的UI框架,这样有可能React Native 有可能真的跑在原生的后端上(OCaml 能在iOS平台编译出原生的汇编)。
BuckleScript未来的发展,我们制定了以下路线:
- BuckleScript把OCaml编译成JavaScript。所以,我们会跟进OCaml的最新发展,并升级到最新版本的编译器。最近OCaml中有很多令人兴奋的新特性,我们会从中受益。例如,Flambda的优化将会使我们的编译器更快。
- 我们将与其他的团队(Bloomberg内部的或外部的)合作,为BuckleScript提供更多的绑定(NodeJS、Electron和React)。
- BuckleScript的编译器也被编译成JavaScript,这意味着用户不仅可以在任意地方运行OCaml/Reason,同时也可以在任意地方写OCaml/Reason。我们将所有的东西都打包成一个JavaScript文件,用户可以快速上手不会遭遇JavaScript疲劳。同时,我们也将提高我们的playground,使之成为更好的Web IDE。