为什么不是铁锈呢?

2020-09-21 04:29:23

我最近读了一篇批评铁锈的文章,虽然它提出了很多好的观点,但我并不喜欢它。 - 这是一篇很容易争论的文章。总的来说,我觉得我不能推荐一篇批评铁锈的文章。这是一种耻辱, - 直面缺点是重要的,而揭穿低努力/错过知情的批评尝试不幸地接种了实际上好的论点的疫苗。

RUST是一种系统编程语言,它提供对数据布局和代码运行时行为的精确控制,为您提供最大的性能和灵活性。与其他系统编程语言不同,它还提供内存安全 - 错误程序以定义明确的方式终止,而不是释放(潜在的安全敏感)未定义的行为。

然而,在许多(大多数)情况下,不需要最终的性能或对硬件资源的控制。对于这些情况,现代托管语言(如Kotlin或Go)提供了不错的速度、令人羡慕的执行时间,并且由于使用垃圾收集器进行动态内存管理,因此内存是安全的。

程序员的时间是宝贵的,如果您选择Rust,预计会花一些时间来学习Rails。Rust社区在创建高质量的教材上投入了大量时间,但Rust语言很庞大。即使Rust实现会为您提供价值,您也可能没有资源来投资于增长语言专业知识。

Struct Foo{bar:bar}struct Foo;';a&>;{bar:&;&39;a Bar}struct Foo;{bar:&;&39;a mut Bar}struct Foo{bar:box<;Bar&>;}struct Foo{bar:RC<;Bar&>;}struct Foo{bar:Arc<;Bar>;}。

在Kotlin中,您编写类Foo(Val bar:bar),然后着手解决您的业务问题。在Rust中,您需要做出一些选择,其中一些非常重要,需要使用专门的语法。

所有这些复杂性的存在都是有原因的, - 我们不知道如何创建一种更简单、内存安全的低级语言,但并不是每项任务都需要低级语言来解决它。

编译时间是万事万物的乘数。用运行速度较慢但编译速度较快的编程语言编写的程序可能运行得更快,因为程序员将有更多时间进行优化!

Rust故意在泛型困境中选择了速度较慢的编译器,这不一定是世界末日(由此带来的运行时性能改进是真实的),但这确实意味着您必须竭尽全力在较大的项目中争取合理的构建时间。

Rustc实现了可能是产品编译器中最先进的增量编译算法,但这感觉有点像是在与语言编译模型作斗争。

与C++不同,Rust build并不是令人尴尬的并行;并行量受到依赖图中关键路径长度的限制。

Rust还缺少与PIMPL习惯用法类似的东西,这意味着更改一个板条箱需要重新编译(而不仅仅是重新链接)它的所有反向依赖项。

5岁的Rust绝对是一门年轻的语言。即使它的未来看起来很光明,我也会把更多的钱押在“C将在10年内出现”上,而不是“Rust将在10年内出现”(参见Lindy Effect)。如果您正在编写能够持续数十年的软件,您应该认真考虑与选择新技术相关的风险。(但请记住,回想起来,在90年代选择Java而不是Cobol作为银行软件是正确的选择)。

Rustc编译器 - 只有一个完整的实现,最高级的替代实现mrustc故意省略了许多静态安全检查。目前,Rustc只支持一个可投入生产的后端CPULVM。因此,它对 - 体系结构的支持比C语言要窄,C语言有GCC实现以及许多供应商专用编译器。

最后,铁锈缺乏官方规格。该参考是一项正在进行的工作,尚未记录所有详细的实现细节。

除了Rust之外,系统编程领域还有其他语言,特别是C、C++和Ada。

现代C++提供了提高安全性的工具和指导方针。甚至有人提议使用类似铁锈的生命周期机制!与铁锈不同,使用这些工具并不能保证没有内存安全问题。但是,如果您已经维护了大量C++代码,那么检查遵循最佳实践和使用杀菌器是否有助于解决安全问题是有意义的。这很难,但显然比用另一种语言重写容易!

如果您使用C,您可以使用形式化的方法来证明没有未定义的行为,或者只是详尽地测试所有东西。

如果您不使用动态内存(从不调用空闲),则Ada是内存安全的。

在成本/安全曲线上,生锈是一个有趣的点,但远不是唯一的点!

生锈工具有点碰运气,基线工具、编译器和构建系统(CARAD)经常被认为是同类中最好的。

但是,例如,一些与运行时相关的工具(最著名的是堆分析)就没有 - 如果没有运行时就很难反映程序的运行时!另外,虽然集成开发环境的支持还不错,但它远没有达到JAVA级别的可靠性。如今,在RUST中不可能实现数百万行程序的自动化复杂重构。

不管Rust的承诺是什么,当今的系统编程世界使用C语言,并由C和C++组成,这是不争的事实。Rust故意不试图模仿这些语言 - ,它不使用C++样式的类或CABI。

这意味着世界之间的集成需要显式的桥梁。这些不是无缝的。它们是不安全的,并不总是完全零成本的,并且需要在语言之间同步。虽然分段集成的一般承诺是成立的,工具也迎头赶上,但在此过程中存在意外的复杂性。

一个特别的问题是,Cargo固执己见的世界观(这对纯铁锈项目来说是件好事)可能会让它更难与更大的构建系统集成。

“使用LLVM”并不是所有性能问题的通用解决方案。虽然我不知道C++和Rust在规模上比较性能的基准测试,但不难列出Rust相对于C++留下一些性能的情况列表。

最大的问题可能是RUST的移动语义是基于值的(机器代码级别的 - )。相比之下,C++语义使用特殊的引用,您可以从其中窃取数据(机器代码级别的指针)。理论上,编译器应该能够看透副本链;但实际上它通常不能:#57077。一个相关的问题是没有放置新的memcpy RUST有时需要将字节复制到堆栈中,而C++可以在适当的位置构造东西。

有点有趣的是,Rust的默认ABI(它不稳定,以使其尽可能高效)有时比C:#26494的更差。

最后,虽然从理论上讲,由于更丰富的别名信息,锈色代码应该更高效,但启用与别名相关的优化会触发LLVMbug和编译错误:#54878。

但是,要重申的是,这些都是精心挑选的示例,有时会出现另一种情况,例如std::Unique_ptr有一个Rust‘s Box所缺少的性能问题。

一个潜在的更大的问题是,Rust在定义时检查了泛型,其表达能力不如C++,因此,一些用于高性能的C++模板技巧不能在Rust中使用良好的语法来表达。

对于Rust来说,一个比所有权和借款更核心的想法可能是不安全边界的想法,即通过在不安全的块和功能后面描述所有危险的操作,并坚持为它们提供一个安全的更高级别的接口,就有可能创建一个既具有安全性又具有安全性的系统

很明显,这个承诺在实践中是可行的:模糊生锈代码挖掘的是恐慌,而不是缓冲区溢出。

首先,没有Rust内存模型的定义,因此不可能正式检查给定的不安全块是否有效。在正在进行的运行时验证器中有“Rustc做或可能依赖的事情”的非正式定义,但实际模型是不确定的。因此,可能有一些不安全代码在今天的实践中运行良好,明天可能被宣布为无效,并在明年被新的编译器优化打破。

其次,还有一种观点认为,不安全块实际上不是模块化的。足够强大的不安全块实际上可以扩展语言。单独使用两个这样的扩展可能很好,但如果同时使用则会导致未定义的行为:观察等价和不安全代码。

经济学(“很难雇佣生锈的程序员”) - 我觉得“成熟度”一节抓住了它的本质,这不能归结为鸡和蛋的问题。

依赖项(“stdlib太小/所有东西都有太多DIP”) - 考虑到货物和语言的相关部分有多好,我个人认为这不是问题。

动态链接(“铁锈应该有稳定的abi”) - 我不认为这是一个强有力的论据。单形化与动态链接从根本上是不兼容的,如果您真的需要的话,还有C ABI。我确实认为这里的情况是可以改善的,但我认为这种改善不一定是针对铁锈的。