备受期待的 Julia 1.0 版本的发布,是近十年来构建一个供有抱负的程序员使用的语言的成果。JuliaCon2018 举办了一场活动来庆祝这一时刻,社区在活动中正式联合发布了 1.0.0 版本。
Julia 的第一个公开声明列出了对该语言的一系列要求。
我们想要一个开源的、使用自由许可证的语言。我们想要 C 语言的速度和 Ruby 的动态性。我们想要一个同像的语言,拥有 Lisp 类型的真正宏,但同时拥有像 Matlab 一样直观且熟悉的数学记号。我们想要一个像 Python 一样可用于通用编程的语言,像 R 一样易于进行统计分析,像 Perl 一样自然地处理字符串,像 Matlab 一样强大地进行线性代数运算,像 shell 一样擅长将程序连接在一起。我们想要一个非常容易学习的语言,但也要让最资深的程序员感到满意。我们想要一个交互式语言,并且也是一个编译型语言。
一个充满活力和富有成效的社区围绕着这门语言发展起来,来自世界各地的人们不断地改进和完善 Julia 以实现其目标。超过 700 人为 Julia 本身做出了贡献,还有更多人开发了数千个令人惊叹的开源软件包。总之,我们构建了一个具有以下特性的语言:
快速:Julia 从一开始就被设计成具有高性能。Julia 程序被编译成针对许多平台的有效本地代码,借助 LLVM 实现。
通用:它使用多重派发作为范式,使表达许多面向对象编程或函数式编程模式变得容易。
标准库提供了异步 I/O、进程控制、日志记录、性能分析、包管理器等等。
技术性:它擅长数值计算,拥有出色的数学语法,对许多数据类型提供了广泛的支持,并且默认包含并行性。其多重派发是定义数值类型和数组类型的自然契合点。
可选类型:Julia 拥有一个丰富的语言来描述数据类型,类型声明可用于阐明和巩固程序。
可组合:Julia 包可以无缝地组合在一起。单位数量矩阵、货币和颜色的制表数据——一切都能正常工作,而且速度很快。
请下载1.0 版本的 Julia来试用它。如果你正在更新 Julia 0.6 或更早版本中的代码,建议你首先使用 0.7 版本作为过渡。一旦你的代码不再出现警告,你就可以切换到 1.0,而不会损失任何功能。注册的软件包正在利用这个过渡阶段并发布与 1.0 兼容的更新。
Julia 1.0 最重要的优势当然是 API 稳定性的承诺:你为 Julia 1.0 编写的代码将在 1.1、1.2 等版本中继续运行。该语言已“完成”。核心开发者和社区可以专注于软件包、工具以及构建在坚实基础上的新功能。
然而,Julia 1.0 不仅仅是关于稳定性,它还引入了新的强大语言创新。从 0.6 版本以来的一些新增功能包括:
一个新的内置包管理器带来了巨大的性能提升,并且比以往任何时候都更容易安装软件包及其依赖项。它还支持每个项目的特定环境以及精确的状态记录,以便于与他人(以及未来的你)共享应用。最后,重新设计还引入了对私有包和存储库的内置支持。你可以使用与开放包生态系统相同的工具来安装和管理私有包。JuliaCon 演示文稿总结了新的设计和功能。
Julia 现在有一个新的缺失值规范表示形式。能够表示和处理缺失数据对于统计和数据科学至关重要。以 Julia 的风格,新的解决方案是通用的、可组合的且快速的。任何通用集合都可以通过允许元素包含预定义的值 missing
来有效地支持缺失值。在早期版本的 Julia 中,“联合类型”集合的性能会非常慢,但编译器的改进使得 Julia 现在可以与其他系统中 C 或 C++ 中的缺失值速度相媲美,同时仍然更加通用和灵活。
String
类型现在可以包含任意数据。你的程序不会因为单个无效的 Unicode 字节而在数小时或数天后崩溃。所有字符串数据都会被保留,同时会指示哪些字符有效或无效,允许你的应用在包含所有不可避免的复杂性的真实数据中安全可靠地使用。
广播一直以来都是一个具有便捷语法的关键优势——现在它比以往任何时候都更加强大。在 Julia 1.0 中,很容易将广播扩展到用户类型并在针对 GPU 和矢量化硬件的计算中实现它,为未来的进一步改进铺平了道路。
命名元组是新增的功能,允许以名称和高效的方式表示和访问数据。例如,你可以将一行数据表示为 row = (name="Julia", version=v"1.0.0", releases=8)
,并以与不便的 row[2]
相同的速度访问其 version
列,即 row.version
。
点运算符现在可以被重载,从而允许类型使用 obj.property
语法来表示不只是访问或设置结构体字段的行为。这对于简化与基于类的语言(如 Python 和 Java)的互操作性特别有用。这也允许重载语法以获取数据列并使其与命名元组匹配:你可以编写 table.version
来访问表的 version
列,或者 row.version
来访问单个行的 version
字段。
Julia 的优化器在许多方面变得更加智能,这里无法一一列举,但其中一些值得一提。优化器现在允许我们通过函数调用传播常量,从而实现比以前更好的死代码消除和静态求值。编译器现在也更善于避免在长期存在的对象周围分配短暂的包装器,从而允许程序员在不牺牲性能的情况下使用高级抽象。
参数化类型的构造函数现在使用与声明时相同的语法进行调用。这消除了一个奇怪但令人困惑的语法障碍。
迭代协议已完全重新设计,以便于实现各种类型的可迭代对象。不再是——start
、next
、done
——现在为 iterate
函数定义了一个或两个参数的方法。这通常允许使用单个方法和初始状态的默认值来定义迭代。此外,可以实现仅在尝试并未能生成值后才知道是否已完成的迭代器——正是 I/O、生产者/消费者等中普遍存在的迭代器类型。Julia 可以直接正确地表达这些迭代器。
作用域规则已得到简化。引入局部作用域的构造现在以一致的方式执行,无论预先存在的全局名称绑定是否存在。这消除了以前存在的“硬/软”作用域的区别,这意味着 Julia 始终可以静态地确定变量是局部变量还是全局变量。
语言本身变得更加精简,许多组件被分解到“标准库”中的软件包中,这些软件包与 Julia 一起发布,但不是“基础”语言的一部分。如果你需要它们,只需导入(无需安装),但你不会被迫这样做。将来,这将允许标准库独立于 Julia 进行版本控制和更新,从而使其能够更快地发展和改进。
我们广泛地审查了所有 Julia API 以改进一致性和可用性。许多传统的模糊名称和低效模式已被重命名或重构,以优雅地匹配 Julia 的功能。这促使了更一致地处理集合的变化,并确保参数顺序在整个语言中保持一致,以及在适当的 API 中纳入(现在速度更快的)关键字参数。
大量外部软件包是专门围绕 Julia 1.0 的优势构建的,例如:
数据处理和操作的生态系统已围绕缺失值重新组织。
Cassette.jl 提供了一个强大的机制,用于将代码转换传递注入到 Julia 编译器中,从而允许事后分析和扩展现有代码。除了调试器和性能分析器等程序员工具外,它还可以实现机器学习任务的自动微分。
对异构架构的支持得到了极大增强,并且进一步与编译器的内部工作原理解耦。Intel KNL 在 Julia 中运行良好。Nvidia GPU 通过 CUDANative.jl 进行编程,并且正在开发 Google TPU 的移植版本。
这些只是一些改进。有关完整更改列表,请阅读 0.7 NEWS 文件。在我们最初的“为什么我们创建 Julia”博客文章中(2012 年),我们写道:
它尚未完成,但现在是时候发布我们创建的名为 Julia 的语言的 1.0 版本了。
也许我们对 1.0 版本发布的时间有点太早了,但时间终于到了,这是一个很棒的版本。我们真的为我们所取得的成就感到自豪,数千名程序员以各种方式为这门真正现代的通用和数值编程语言做出了贡献。