track image

Hack Tech Talk 2015/03/05

今晚去FacebookMenlo Park主园区听了个关于Hack Type System的tech talk。挺有趣的,稍微写点啥发出来吧。新鲜滚热辣 >_<

第一次去,进到Facebook园区觉得里面就像一个小型城市一样。有点回到了阿里西厂园区的感觉——只是占地面积更大的感觉。

本文不关心Zend PHP、HHVM、Hack之间的爱恨恩怨。那些话题留给language zealot们慢慢咬。

内容慢慢更新嗯。

Hack项目与Hack类型系统

今晚的活动由manager(Damien Sereni)开场,然后由Josh Watzman主讲。演讲有录像,日后会放出。等出来之后我会把链接更新过来。

更新(2015-03-27):录像总算放出来了:Heresy! Combining type systems with PHP(请自备梯子)

演讲内容主要是:

  • Hack项目概要、与PHP的关系
  • Hack的类型系统的功能和当前实现的局限
  • Hack的类型检查器(type checker)的实现细节

首先Hack项目是什么。

官网:hacklang.org/

GitHub代码仓库:github.com/facebook/hhv

Hack项目包括:

  • 一门编程语言语言:Hack Programming Language。
  • 一个类型系统,及其对应的类型检查器
  • 与HHVM衔接的前端编译器

Hack编程语言是PHP的方言,在PHP 5的基础上添加了一套类型系统和与其配套的类型标注语法,另外还添加了一套集合库和一些方便的语言特性,例如比PHP的闭包更简洁的lambda语法、async语法之类。最重要的是它仍然可以完全兼容原本的PHP 5,所以可以从现有的PHP代码平滑过渡到使用越来越多的Hack特性。当前的facebook.com就跑在Hack上——当然,既然原本的PHP也可以算作Hack,那⋯ >_<

Hack非常非常强调“实用主义”(pragmatism),不玩纯学术,不做高大全。一切皆为Facebook的具体使用环境而设计。Facebook已经有非常大量的PHP,完全替换掉它们迁移到一种新语言不现实而且也没必要。PHP的开发效率确实还不错,(只要知道它的坑在哪里之后别掉坑里)开发-调试-发布循环可以很块。但程序的错误一定要到调试运行时才有机会看到也时普遍让开发者头疼的问题。


Hack语言的设计目的主要是为了相对PHP提高开发效率,而并非提高运行效率——后者还是交给HHVM自己解决。Hack给PHP添加了类型标注主要也是为了给开发者提供友善、有用但不碍事的类型检查提示信息,把程序里潜在的类型错误报告出来,让开发者能尽早发现和修复bug,而不必等到运行时。因此Hack的类型系统不是为了赶时髦,而是尽可能的适应原本PHP的语义,让原本PHP就存在的类型变得更明显、更容易检查。就这个意义上说,Hack与PHP的关系跟TypeScript与JavaScript(ECMAScript 5 / 6)的关系相似。

Hack的类型系统使用了渐进式类型系统(gradual typing)的设计,也就是说类型系统能接受从完全没写类型标注到完全标注好的程序。它从Edwin Smith得到了大量影响。Edwin以前在AdobeActionScript 4的主要成员之一;Hack的gradual typing受ActionScript 4的影响非常深。之前我以为Erik Meijer在Hack的设计上有更大的影响,但去参加这个活动都没怎么听大家提起梅姐,略失落。

当下有不少较新的语言都采用了gradual typing设计,例如DartTypeScriptPerl 6等。

关于ActionScript 4的gradual typing设计,可以参考这篇论文:The Ins and Outs of Gradual Type Inference。论文和实验虽然都是在ActionScript 3上做的,但其实它是为ActionScript 4做的铺垫。

关于gradual typing的更多资料,可以参考这里:samth/gradual-typing-bib · GitHub,还有这个

除了gradual typing外,Hack的类型系统还包含别的当下流行的特性:


目前能运行Hack编程语言的主要就是HHVM。虽然也有Hack Transpiler可以把Hack转换为PHP以便在普通PHP环境里运行(就像TypeScript编译为JavaScript那样),但始终不咋受关注。

Hack的实际代码分为两部分:类型检查器HHVM的前端。类型检查器的任务是分析Hack源码,做类型检查并报告错误。它并不做任何代码生成;而HHVM一侧,在原本的PHP语言的前端编译器之外另外专门写了一个Hack语言的前端,将Hack语言编译为HHBC(HipHop Bytecode)然后交给HHVM的后端去执行。

历史原因使得这两部分没有任何交互而且存在大量重复代码。Josh表示今年内有望把类型检查器改造得与HHVM更紧密的整合起来,让它成能够直接生成HHBC,届时就不必维护两个有大量重复代码的项目了。但要让HHVM有效使用Hack的类型标注的好处,必须略为改造HHBC让它能记录更多类型信息才行。

Hack类型检查器和HHVM的JIT编译器都要做类型检查,但两者的出发点和取舍还是有所不同。前者的目标是“prove the negative”,找出肯定有类型错误的地方,并相应报错;后者是“prove the positive”,找出某个变量在某处肯定是某个特定类型而不是其它类型的情况,并相应优化。这使得Hack类型检查器报告的类型信息比HHVM的JIT编译器做优化所需的类型信息弱,因而也不能直接用于优化。


这次演讲的主角就是Hack的类型检查器。它大部分用OCaml实现,并有少量C代码实现些特殊功能。

Hack类型检查器主要由Julien VerlaguetJosh Watzman实现。Julien来自法国Paris VI University,所以很自然的选择了用OCaml。

Hack官网上有个Tutorial,里面可以直接在页面上对用户输入的Hack代码做类型检查。这是通过把OCaml编写的类型检查器编译成JavaScript来在浏览器里运行的。

类型检查器的工作流程分为5个步骤(phase)。每个步骤都只依赖之前的步骤计算所得数据而不需要同步骤内别的部分的计算数据,便于并行化,以便应对Facebook庞大的PHP/Hack代码量。

这5个步骤是:


这个流程的大入口(之一)可以在这里找到:type_check

Josh很热心的回答了我的问题,把5个步骤在代码中的入口位置都指出来了:pastebin.com/6rVfpY3f

实际代码的结构并不直接反映出上述的5个步骤。Josh解释说“The actual code is pretty messy and poorly factored.”

(未完待续)



TypeScript, AtScript与Flow

TypeScript: Welcome to TypeScript

AtScript: AtScript Primer

Flow: Flow: A Static Typechecker for JavaScript

Damien Sereni提到在Facebook,用JavaScript写前端的开发工程师跟用PHP写数据部分的开发工程师的风格不太一样。这使得他们对工具的需求也不同。所以Flow虽然跟Hack是同一个团队开发的,但设计却非常不一样。

Facebook尝试过用TypeScript,但发现TypeScript无法满足他们的需要,然后才觉得自己开发Flow。TypeScript的类型检查边界是函数级别的,函数的参数和返回值类型都要声明才能有效的做类型检查;而Flow的类型检查边界是文件级别的——只要在文件层面上声明类型即可。

Flow同样用OCaml实现,然后也有少量C。它与Hack类型检查器有一些共享代码。

Flow团队有跟微软的TypeScript团队和Google的AtScript团队协调,让这三种JavaScript方言可以尽可能兼容。Flow能够直接读取和使用TypeScript的.d.ts Definition File


八卦部分

聊天的时候听说了各种以前没咋关心的八卦。其实有些想想似乎更早之前也听说过,然后就忘记了。

一个是Hack语言的名字的八卦。这门语言的名字似乎是公认的糟糕,Josh的说法是“跟Go共为最糟糕命名” >_<

一个是HHVM的开发团队的八卦。HHVM Open Source、Hack、Flow这几个项目都是同一个manager——前面提到的Damien Sereni——带的。而HHVM内部开发团队在Facebook叫做“HHVM JIT team”。

这“HHVM JIT team”与“HHVM Open Source team”的关系是:前者是原本的HHVM团队,继续肩负着开发HHVM核心的任务;后者主要是为了支持外部的HHVM用户,修补外部用户遇到的bug、从PHP移植外部用户需要(但Facebook自己没用到)的扩展,例如MongoDB扩展啥的。两个团队是在同一份代码上工作,但任务和受众不同。

HHVM Open Source team主要服务的对象是像百度、Etsy之类的HHVM外部客户。Facebook能养着一个组专门服务外部客户真好⋯

一个是PS4Orbit OS是基于FreeBSD裁剪和定制的。内核裁剪和写死了一些东西,例如semaphore的数量有个写死的上限之类的;然后新写了些驱动程序。然后PS4的主菜单界面程序VShell,整个是用C#写的,基于Mono运行在PS4上。这个Mono实例只用于运行VShell,而不用于运行任何其它东西(例如游戏)。Sony最近还试着给Mono提交了写patch来修PS4平台上遇到的问题。

看到CoreCLR开源他们似乎也很激动⋯咳咳。搞不好以后PS4上就流淌着微软代码的血液了(扭头看向XBox One⋯

一个是Wind River重启了GCC小组,重新开始大搞编译器。真好。被Intel大财主收购之后的Wind River仍然有自由做自己的项目,只是Intel点名要做的项目无法忽略了而已。

文章被以下专栏收录
3 条评论
推荐阅读