期待已久的 Julia 1.0 版本发布,标志着近十年来为打造一款面向贪婪程序员的语言而付出的努力终于结出硕果。JuliaCon 2018 举办了庆祝活动,社区在招待会上正式将版本号设置为 1.0.0。发布会还伴随着一场演讲: 关于 Julia 的简短历史和对未来的大胆猜想.
Julia 是 首次公开发布,对该语言提出了一些强烈的要求
我们想要一种开源的语言,使用自由许可证。我们想要 C 的速度和 Ruby 的动态性。我们想要一种同像的语言,拥有像 Lisp 那样的真正宏,但同时又像 Matlab 一样拥有明显、熟悉的数学符号。我们想要一些像 Python 一样适用于通用编程,像 R 一样易于统计,像 Perl 一样自然地处理字符串,像 Matlab 一样强大地进行线性代数,像 shell 一样擅长将程序粘合在一起。一些学习起来非常简单,同时又能让最资深的程序员感到满意的东西。我们希望它具有交互性,并且希望它能够编译。
围绕着这种语言,一个充满活力和蓬勃发展的社区已经成长起来,来自世界各地的人们不断迭代改进和塑造 Julia,以追求这一目标。超过 700 人为 Julia 本身做出了贡献,更多的人开发了数千个令人惊叹的开源 Julia 包。总而言之,我们打造了一种语言,它
快速: Julia 从一开始就设计为高性能语言。Julia 程序通过 LLVM 编译为多个平台上的高效原生代码。
通用: 它使用多重派发作为范式,使其易于表达许多面向对象和函数式编程模式。标准库提供了异步 I/O、进程控制、日志记录、性能分析、包管理器等等。
动态: Julia 是动态类型的,感觉像脚本语言,并且很好地支持交互使用。
技术: 它擅长数值计算,语法非常适合数学,支持许多数值数据类型,并且开箱即用地支持并行计算。Julia 的多重派发非常适合定义数字和数组类型的数据类型。
可选类型: Julia 拥有丰富的描述性数据类型语言,类型声明可用于澄清和巩固程序。
可组合: Julia 的包自然地很好地协同工作。单位量的矩阵,或货币和颜色数据表的列,都可以正常工作,并且具有良好的性能。
现在就通过 下载 1.0 版本 来试用 Julia。如果你正在将代码从 Julia 0.6 或更早版本升级,我们建议你先使用过渡版本 0.7,它包含弃用警告,可以帮助你完成升级过程。一旦你的代码没有警告,你就可以切换到 1.0,而不会有任何功能上的改变。已注册的包正在利用这个过渡阶段,发布与 1.0 兼容的更新。
当然,Julia 1.0 中最显著的新特性是承诺语言 API 稳定性: 为 Julia 1.0 编写的代码将在 Julia 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 的编译器,从而实现对现有代码的事后分析和扩展。除了用于程序员的仪器,如性能分析和调试,它甚至可以实现机器学习任务的自动微分。
异构架构支持已经得到了很大改进,并且进一步从 Julia 编译器的内部细节中分离出来。英特尔 KNL 在 Julia 中可以正常工作。Nvidia GPU 使用 CUDANative.jl 包进行编程,并且正在移植到 Google TPU。
还有无数其他的改进,无论大小。有关更改的完整列表,请参阅 0.7 NEWS 文件。在我们最初的 “为什么我们创建了 Julia”博客文章 中,我们在 2012 年写道
它还没有完成,但现在是发布 1.0 版本的时候了——我们创建的语言叫做 Julia.
我们可能在提到即将发布的 1.0 版本时有点草率,但现在终于到来了,而且这是一个了不起的版本。我们对数千人以多种方式为这款真正现代的数值和通用编程语言做出的贡献感到无比自豪。