来自微软的Mads Togersen在近期所提出的一条提议,即在C#语言中加入对不可空引用类型的支持在.NET社区中引起了热烈的争论。人们对此提议的反应大相径庭,既有人对此表示赞赏,也不乏倾向于保持现状的意见。
在Reddit上,这条提议引起了大量关于向后兼容性方面的疑问。Strilanc认为,如果应用了这一特性,按照这条提议的做法无法实现现有应用的平滑过渡:
这条提议还有待改进,它对于保证二进制兼容性、源代码兼容性以及现有代码的渐进式过渡方面还存在着一些考虑不周的情况。
还有一方面的顾虑在于对于外部类库的向后兼容性,正如Maplemario所说:
那么问题来了。假设我要使用一个旧的类库,其中的函数都返回类型T,无法它是否是可空的。现在,该提议产生了语言范式上的转变,它将T视为不可空的T类型,而我所调用的某个函数却有可能返回null(在编写这个类库时,这种做法是合法的)。如果这种场景在整个程序中是一个偶尔才需要进行测试的用例,那么在理想的情况下,项目文档将指出这一点,而我在阅读文档后就知道应当在调用时进行空检查。或者因为我记得这是一段陈旧的代码,因此我将始终进行空检查。而在实际情况下,由于“T即代表着不可空的T”,因此我无需再进行空检查。如此一来,这段程序就会在我对空指针进行取值时崩溃。
人们也在热烈地讨论这一提议的替代方案。用户00Davo倾向于使用一种新的符号,以表示不可空类型。
我也乐于让纯粹的T类型总是代表不可空的引用,而只有T?才能够接受空值,但这种改变对于向后兼容性来说就是一场恶梦。如果能引入一个全新的、明确的不可空引用符号,那么向后兼容性就会坚挺许多。比如使用T!符号,如何?
而在有些人看来,实现这一提议会造成的问题过多了。Number127建议将静态分析作为一种替代方案:
遗憾的是,目前来看,如果要以一种优雅的方法引入不可空引用类型,会造成过多的兼容性问题。我认为最有希望的替代方案是在维持目前的类型系统的情况下,通过静态分析技术以检查某个引用是否能够保证不为空。
在GitHub的页面上,人们同样在讨论静态分析这一方案。Paulo Morgado对此进行了更进一步的阐述,他表示这条提议其实就代表了静态分析的使用:
如果我的理解没错,这条提议其实就是一种增强版的方法契约而已。编译器在这里不会做出什么担保,更不用说运行时了。编译器所做的无非是对于那些声明为可空的变量进行数据流的分析而已。
在另一个话题中,Tomas Petricek指出:这条提议必须考虑到其它CLR语言,例如F#:
该提议能否详细地说明一下如何在CLR级别保存可空的标注信息?(我猜测这些标注应当并不具有运行时的意义,它们只会表现为某种.NET attribute,或某种其它类型的元数据?) 我希望未来某个版本的F#编译器能够辨识并理解这些标注信息,并定义某种“严格”模式,可空的类型在这种模式中将自动地暴露为option<'T> (或者差不多意思的某种类型)。
对于不可空引用类型的争论其实并不新鲜,在过去几年中,对这一问题已经进行了多次讨论。正如原微软的首席开发者Eric Lippert所说,在一个已具有15年历史的语言中添加不可空引用是一项浩大的工程。
查看英文原文:Debate: Adding Non-nullable References to C#