|
我先说说主要结论,主要原因有两个:历史遗留问题,更新成本和教育问题(程序员来源)
历史遗留是很好理解的,只要还有旧的代码要继续运行,即使一门语言再不好也会有人继续使用维护已有的代码(只不过我们也可以认为这种语言已经死了)。考虑到人们已经用C/C++写了大量的基础设施,把它们全部替换是大量浪费资源(就好比现在5G,4G,一样,出了新的更高速的通信技术,旧的仍然保留下来,就是因为全部更换实在是太浪费了)
然后是更新成本,即使这世界上存在这一门比C与C++更加好用的编程语言,更加高性能,接近底层,人们也不一定就会投入这门语言中。因为获得的收益可能完全小于迁移成本。别忘了,在当今竞争激烈的商业时代,如果一个代码运行的好好的,谁也没有动力要乱改这些代码。而且这个东西是由供求关系决定的,如果大公司有需要C/C++(因为各种各样的原因),C/C++就完全不会被淘汰,就一定会有人继续学习。
我想说的是,教育才是C/C++始终能够深入人心的重要原因。
很多CS的人在大学阶段受的教育都是用C/C++语言(当然也有别的语言,只不过前面两个是必备的)来传授的,比如操作系统原理,计算机架构,并行计算(很大一部分原因就是这些基础设施也是用C/C++写的)。为什么用C/C++呢?难道是因为大家在写作业的时候需要用到高性能吗?是因为C/C++一定就是最适合的所有这些问题的语言吗?
理论上说如果只是传授这些计算机知识的原理的话,我们完全可以发明一门基于伪代码的语言(就像大多数书上的一样),它要满足以下要求:
1.它很简洁直观,使得我们便于集中精力到我们要研究的问题上。
2.它反映计算机底层的细节,比如说应当手动分配内存,比如应该是编译的。
3.因为我们不需要用太多的抽象,所以类型系统应该比较简单,不要有花里胡哨的泛型等玩意。
这些要求很合理,作为教学的工具自然不要太复杂,毕竟教学时间也是有限的。
满足这三个要求的东西的编程语言,形式上就要等价于C/C++。
首先我们应该选择一门静态语言,因为一般静态语言才能编译(成便于研究和debug的机器码),然后因为1,3我们需要一个配备有简单的类型系统的编程语言。什么类型系统最简单(最符合直觉),基于简单lambda演算的语言肯定最简单,没有一点多余的抽象,再加上没有自动内存管理我本质上我们就得到C了(当然指针是一个问题,因为可以有和C类型系统等价但是不支持指针的编程语言,但是因为我们要求接近机器底层,所以对于地址的抽象还是要有的)。。。再复杂一点的类型系统我们就可以得到一个面向对象的语言了C++(现在是基于模板了,所以面向对象一斤是不准确的了)。
所以实质上我们要同时满足1,2,3要求的语言就寥寥无几,再加上C/C++在工业界有很大的应用,所以干嘛不用它们来教书?还方便同学们动手实践呢!
但是这不代表别的编程语言就不能很好的管理它们的内存,不代表别的编程语言设计上就不如C/C++,不代表别的编程语言就不能很好利用CPU了(我这里说的主要是静态编程语言)。最重要的问题是,大多数C/C++以外的语言有着很复杂的抽象(例如Haskell),要是我们在刚学的时候就教这些东西,大家就会云里雾里的,什么是高阶函数,什么是类型变量(这又牵扯到类型理论)?但是一开始我们要学的东西是计算机底层的东西,不是编程语言理论,这些用于生产环境的高级编程语言很多时候又用抽象屏蔽了底层实现的细节(屏蔽细节不等于没有好好利用计算机底层,看起来不像机器语言,不代表最后执行起不像机器语言一样快),也自带垃圾回收(这一点就可以筛掉一大堆语言了),所以教起来效果就可能不好。要是我们用C这样就好解释了,每一个malloc对应着一个内存分配,结构体是一片内存划分成不同的域等等,但是Haskell就不好说了,谁知道一个sum type或者递归类型在内存里面怎么摆放的,是box了还是unbox的(你可以知道,但是要查文档)。
很多时候大家以C/C++接近机器底层(例如说,有指针的抽象,有手动分配内存),性能很高,来论证别的语言在这一点上不如C/C++(当然也确实有很多动态编程语言比不上,这要承认),要是一个语言没有指针,没有一个malloc的函数(或者别的各种各样的理由),就是不合机器底层的抽象。从本质上这就是在排挤别的编程语言的抽象。我就说说Haskell好了(我用Haskell举例就是想说明即使是Haskell这样的异端语言一样也有对同一个问题不同的处理方法),用malloc分配内存完全可以分配一个参数化类型的数组来代替呀(就是说把malloc包装在一个数组的类型构造器中,并且这个类型构造器是泛型的),在Haskell中一样指针的对应物,只不过它叫Ref(具体名字我记不得了,必须在一个IO Monad中使用,因为有副作用),当然你会争论这个指针不能用来做算术,只是一个引用,但是要做算术的指针应该使用前面所说的在数组上分配的内存块上做才有意义。
所以在大学阶段C/C++用的最多,大家最了解(非常深入的了解),懂的人多了自然话语权上就占有优势了,了解多了自然就可以说出一大堆好处,说出一大堆产品,反观其他编程语言(我说的是不是Python和Java这种),本来使用者就不多,自然势力就很小。我再用Haskell举例,大家总是吐槽Haskell是一个学术语言,没有实际用途,但是问题是很多人学Haskell的时候花的精力就不及C/C++多,所以了解就不深入,很多人知道的还是map,reduce之一套,但Haskell还有Monad和各种各样的语言扩展,涉及到很深的PL理论,而且Haskell一样有一本很厚的Reference book,对比大家学C/C++都看过几本书,有多少人学Haskell的时候看过几本书。而且有的人提到了写编译器,用Haskell来写的编译器也不少吧(不要争论Haskell底层是LLVM然后就和C++有关了,这毫无意义)不是非要把基础设施重写一遍才叫写了一个编译器。
我想说一下,大部分人认为的编程语言=C/C++ + Python+Java+Javascript,我认为的还额外包括Rust,Julia,Haskell,Prolog这些不入大流的编程语言。。。大家要看到这些小众编程语言,在资源非常有限的情况下还能作出了不少杰出的作品,在编程语言日益饱和的今天,这些语言能够活着就是很不容易的了,开发者精力是很有限的,不要觉得这世界上只有C/C++关心性能,很多这些开源编程语言作者也想提高程序的性能,但是很多时候有别的更加重要的事情要做,所以才搁置了(发明新的编程语言的目的,很大程度上是为了提供新的抽象,以及对固有模式进行优化,而非以用户完全手动控制为目的,所以提高编译器的能力(或者解释器)是所有编程语言的第一要务,C/C++性能来源的很大一部分,是编译器赐予的)。
所以总结一下,最重要的原因是:
1.C/C++是大家了解最多的编程语言,是教学时良好的“模型语言”,潜移默化的成为了标准,在这个领域大家也就不再发明有重复功能的语言了(除非有新的痛点要解决,比如说大家发明了Rust来解决内存问题)
2.很多工业设施都是用C/C++写的,所以没有动力更新
3.因为1,2,所以大家投入了更多的精力到C/C++中,由于马太效应,C/C++比别的语言更有优势。
大家一定要意识到,编程语言是一个有trade-off的事情,很多时候我们总是要牺牲掉一些东西换另外一些东西。就以异常处理为例,常见有三种方法
1.返回一个不可能值(例如-1),但是没有自己的类型
2.返回一个错误值(Error Code),可以有自己的类型(Maybe monad也在此列)
3.自己抛出一个错误打断程序
这三种方法一个比一个安全,但是一个比一个代价大,而且一旦选择一种就不能随便改动(虽然一个编程语言从能力上说3种可以支持,但是一般只有一种会成为主流的方法,就是说一种最佳实践)。谁不想要性能?但是在安全面前大家也要权衡一番,所以根据不同的应用大家采用了不同的设施,很多语言采用了3,追求部分性能的语言用了2,还有一些语言(如C语言)用了1。所以每个编程语言都是对某个特定问题的一个特定解决方案,没必要因为某个短板就互相看不起。 |
|