备受期待的 Julia 语言 的 1.0 版本凝聚了十年来雄心勃勃的程序员们的辛勤汗水。 在 JuliaCon2018 发布会上,Julia 社区正式宣布 将该版本设置为 1.0.0。
Julia 项目最初是为了满足以下强烈的需求而公开发起的开源项目:
我们想要一种自由开源的语言,它同时拥有 C 的速度和 Ruby 的动态性;我们想要一种同像性(可以将语言的脚本本身当作数据进行处理)的语言, 它有着真正的和 Lisp 一样的宏,但是却像 Matlab 一样有着显然的,类似于数学表达式的标记;我们想要一种既可以像 Python 一样作为通用编程语言的工具, 又可以像 R 一样适用于统计分析,能像 Perl 一样自然地处理字符串,能像 Matlab 一样给力地处理矩阵运算,它还要能像 shell 一样作为胶水将各种程序粘 合在一起;我们想要一种简单易学的语言,同时它还能让最苛刻的魔法师们(hackers)开心。我们希望它是交互式的,但我们也希望它能被编译。
一个充满活力和繁荣的社区围绕着这种语言不断成长,世界各地的人们都在为这个目标而不断努力改进和塑造 Julia。 超过 700 人为 Julia 做出了自己的贡献,更多人创造了成千上万开源的 Julia 包。总而言之,我们创造了这样一种语言:
快速:Julia 从一开始就为高性能而设计。Julia 可以通过 LLVM 而跨平台被编译成高效的本地代码。
通用:Julia 使用多分派作为编程范式,使其更容易表达面向对象和函数式编程范式。标准库提供了异步 I/O,进程控制,日志记录,性能分析,包管理器等等。
动态:Julia 是动态类型的,与脚本语言类似,并且对交互式使用具有很好的支持。
数值计算:Julia 擅长于数值计算,它的语法适用于数学计算,支持多种数值类型,并且支持并行计算。Julia 的多分派自然适合于定义数值和类数组的数据类型。
可选的类型标注:Julia 拥有丰富的数据类型描述,类型声明可以使得程序更加可读和健壮。
可组合:Julia 的包可以很自然的组合运行。单位数量的矩阵或数据表一列中的货币和颜色可以一起组合使用并且拥有良好的性能。
现在可以通过 下载 Julia 1.0 版本 来尝试 Julia。 如果你现在从 Julia 0.6 或者更早的版本开始升级代码,我们建议你先使用过渡性的 0.7 版本, 其中包括了弃用警告(deprecation warning)来指导你的升级过程。一旦你的代码无警告通过, 那么你可以在没有任何功能变化的情况下将代码更改为 1.0 版本。 已注册过的包可以利用这个来过渡并发布与 1.0 版本兼容的更新。
当然,在 Julia 1.0 版本中一个最重要的新特性是对语言 API 稳定性的承诺:你为 Julia 1.0 编写的代码将可以继续在 Julia 1.1, 1.2 中运行。这种语言是“足够成熟的”。基于这样的一个坚实的基础, 核心语言的开发者和社区都可以集中于第三方包,工具,和新特性的开发上。
但是 Julia 1.0 并不意味着稳定,它也带来一些新的,强大并且创新的语言特性。其中一些新的特性是 0.6 开始就有的:
一个全新的内建 包管理器。它比过去的包管理器性能更好,
也更加简单。它也支持虚拟环境和记录当前工作环境的状态然后将其分享给其它开发者或者是自己。最后重新设计的包管理器也带来了 私有包和包的仓库的无缝衔接。你可以用使用开源生态同样的方式用它来管理自己的私有包。这个 JuliaCon 的幻灯片 展示了新设计的包管理器。
Julia 具有新的 对于缺失值(missing value)的正则表达。处理缺失值的能力对于统计学和数据科学是一项基本能力。
在典型的 Julia 写法里,这个解决方案是一般性的,可扩展的也是高性能的。任何一般的集合类型(collection type)都可以简单地通过使用 预先定义好的 missing
变量来有效支持缺失值。而这样的集合类型的性能在过去的 Julia 版本里可能会很慢,但是现在编译器已经 可以使得 Julia 在缺失值的表示上达到类似 C 或者 C++ 的速度,而远比 C 或者 C++ 一般和灵活。
内建的 String
类型可以安全的使用任意的数据类型。你的程序不会因为一个单独的无效 Unicode 字节而失效好几个小时或者好几天。
所有的字符串数据会保留,同时指出哪些字符是有效的哪些是无效的,这样允许你的应用安全并方便地运行在不可避免会出现缺陷的真实世界的数据中。
尽管广播早已成为一项语言的核心特性并且有着方便的语法支持,而现在它将比过去更加强大。在 Julia 1.0 里 为自定义类型扩展广播 和实现高效的 GPU 和向量化硬件上的扩展都
更加容易,为未来实现更高的性能铺平了道路。
可命名元组是一个新的语言特性,它将使得通过名字直接获取数据变得更加高效和方便。例如,你可以这样表示一列数据 row = (name="Julia", version=v"1.0.0", releases=8)
并且通过 row.version
访问 version
的数据,而这和
row[2]
有着相似的性能,但是却更加方便。
点算符现在可以被重载,并且允许类型使用类似于 obj.property
的方式表示某种意义,而不是用来设置和获取合成类型(struct)的
成员。这对于将具有 class
的语言例如 Python
和 Java
翻译到 Julia 来说更加平滑。性质的访问器重载也将使得获取匹配数据的名 称的一列于可命名元组更加一致:你可以写 table.version
来获取表格中的 version
这一列就好像 row.version
会获取 version
这一行的这个元素一样。
Julia 的优化器在诸多方面都更加聪明来,以至于我们无法全部列在这里,但是可以列举一些重要的特点。优化器现在可以在函数
调用之间传播常数变量,这将使得编译器可以比过去更好的消除死代码(dead-code)和进行静态求值。编译器现在也能够对短期存在 的长期对象的封装避免多余的内存分配,这将使得程序员可以使用更方便的高级抽象而不会担心带来性能损失。
参数类型的构造函数现在将使用和声明同样的语法来调用。这将减少一些对语法小的误解。
迭代器协议被重新设计。新的迭代器协议更加简单,而不需要定义三个不同的函数:start
,next
,done
。现在只需定义一个变量
和两个变量的 iterate
函数即可。这将常常使得我们可以简单地通过定义了一个函数参数默认值的函数来实现迭代器。更加重要的是,这将使得 实现一个只有在尝试返回值失败之后才知道需要结束的迭代器成为可能。这种迭代器在 I/O,网络和生产者/消费者模型中普遍存在;而 Julia 现在 可以以更加直接和正确的方式表达这样的迭代器。
作用域的规则被简化了。引入局部作用域的构造将更加一致,而不需要管全局的命名绑定是否已经存在。
这将消除之前存在的 “软/硬 作用域”的区别,也意味着现在 Julia 可以静态地确定变量是局部的还是全局的。
Julia 语言本身变得更加轻量级来,很多部分都不放在来标准库中。这个标准库将和 Julia 一起发布但是不会作为语言的基础依赖。
如果你需要他们,那么只需导入这些库即可(不需要再安装)但是它们不再强制你使用了。在未来这些标准库将会单独被标记版本和更新 以获取更快的改进和升级。
我们仔细地审查了 Julia 的 API,并且提高了它的一致性和可用性。很多费解的命名和低效的实现都被重新命名和重构,使得其能够 更优雅地发挥 Julia 的能力。这将使得使用集合类的方式更加一致和连贯。变量的顺序被确保在整个语言中遵循一个统一的标准,并且 将关键词变量(现在更快了)加入到了 API 中。
围绕 Julia 1.0 的新特性,我们特别地创建了一些新的外部包:
数据处理生态系统通过翻新利用了新的缺失值支持
Cassette.jl 将为 Julia 带来向编译器中注入代码变换,使得
事后分析(post-hoc analysis)和扩展已有的代码成为可能。在除了提供 profiling 和 debugging 这样的工具之外, 这甚至可以用于实现用于机器学习任务的自动微分。
异构计算的支持被大大提高,并且从 Julia 编译器中分离了出来。Intel KNL 系列硬件可以直接使用 Julia。而 Nvidia 的 GPU
也可以通过 CUDANative.jl 来直接编程(无须编写 CUDA 代码),而 支持 Google TPU 的接口也正在开发中。
还有很多没有被列举的大大小小的提高。你可以通过 0.7 NEWS 文件 查看 完整的更新。在我们 2012 年的 "为什么我们创造来 Julia" 博文 里,我们写到:
它还没有完工——但是已经可以发布一个 1.0 版本了(其实等了 6 年才要发布)——我们创造的这个语言叫做 Julia。
虽然对于 1.0 的发布我们放了大家好几次鸽子,但是这一次我们终于正式发布了。 我们真心为所有为这个真正为数值计算和通用编程设计的现代语言的各种形式的贡献的人感到自豪和高兴。