编程语言的发展趋势:从没有分号,到DSL
在上一周的推文《学算法有什么用?唉,对你来说,可能真没用》中,我阐述了一个观点:随着软件行业的逐渐成熟,算法将慢慢不再成为软件行业工作者必备的知识(但一定是信息学相关专业必学的知识)。因为算法将被越来越多的封装,被直接使用。这就好比数据库,近乎是每一个软件项目都必备的需求,但是,近乎每一个软件项目都不会选择重新实现一个数据库。太多现成的数据库工具唾手可得。我们只需要学会怎么使用他们就好了。而怎么使用他们,比重新实现一个数据库,简单不止100倍。
事实上,计算机行业的任何一个细分领域,都在上演着这样的“进化过程”:很多在以前看来是必学的知识,从现代开发的角度看,不一定是必备的。所以,大家会觉得“面试造核弹,上班拧螺丝”。如果你曾经在十五年前,就尝试做一个网页;做一个桌面app(那时还根本没有移动app);做一个游戏;你就会明白我在说什么。一个非常显然的事实是,在十五年前,做一个网页,做一个桌面app,做一个游戏,相应的成本,都是现在的100倍以上,而最终得到的结果,搞不好不足现在的百分之一。这一万倍的差距,不是因为今天的我们更聪明了,而是因为,行业在发展。今天的我们,不仅仅是“站在巨人的肩膀上”,更是“站在了几百万个巨人的肩膀上”。
所以,我经常提醒自己,我能实现这么多复杂的功能,不是因为我有多聪明,而是因为编程在现如今竟是如此的简单。任何一个技术,如果他能被大规模的应用,除了它足够有用之外,还必须具备一个必要的因素——它足够简单。计算机技术在我们这个时代被越来越多,越来越广泛的使用,是因为,计算机技术越来越简单。
在这篇文章中,我想从计算机语言的角度,聊聊编程语言的“演化”。这本身是一个很大的话题,甚至,有很多学者做专门的相关研究。因此,这篇文章的讨论的角度也是极其有限的。大家通过文章的标题就可以看出来,这篇文章将聊到DSL为止。但除了DSL,我们确实还有很多维度去探讨这个话题。以后有机会,我会再逐渐补充我的观点:)
1. 从没有分号,到给人看的编程语言
学习计算机的同学一定了解:分号在计算机编程语言中,有着举足轻重的地位。如果你学习的第一门语言是C,或者C++,或者Java,那么你一定曾经犯过忘记写分号的错误。
但是,如果多接触几门编程语言,就会发现,大多数“现代”编程语言,是完全不需要写分号的。比如Python,比如Swift,比如Go。为什么?原因很简单,在大多数情况下,分号是给机器看的,而不是给人看的。写分号,本质是我们人类在迁就编译器,毕竟,机器是很傻的。
有意思的是,即使是同样一定需要分号的语言,Java也比更底层的C++需要的分号少。比如,下面的例子中,我们同样声明一个学生类。
C++语言:
class Student{
public:
string name;
}; // 注意,在C++语言中,这里必须有一个分号
Java语言:
public class Student{
public String name;
} // 注意,对于Java语言,这里不需要分号!
可以看到,在类声明结束的时候,C++语言这个老古董,还需要加上一个分号,但是Java语言不需要。显然,Java语言的语法规则更加合理。在这里,大括号的结束已经完全可以表示类声明的结束了,多一个分号,对人类来说,是一个额外的“语法负担”。
随着编程语言的逐渐演化,这样的语法负担都将被剔除。如果你学习过Python语言,就会知道,何止是分号消失了,连大括号都消失了。为什么?就是因为大括号也是给机器看的。告诉机器,类声明结束了。从Python的角度看,“旧式语言”有太多的语法规则,使用了过多的字符,来告诉机器如何解析程序。比如分号,比如大括号。这使得这些语言猛地看上去,包含一大堆和程序本身所表达的逻辑完全无关的字符。所以,Python在努力减少这样的语法。
但与此同时,Python在另一些语法中,却在添加更多的字符。最典型的就是三目运算符“?:”,在Python中没有了。为什么?三目运算符虽然形式更简单,但是这个“简单的形式”也是给机器看的,不是给人看的。
比如我们要根据score这样一个变量的值,返回“Perfect”或者“Not Perfect”这样的字符串,在C++或者Java这样的语言中,我们写出的逻辑大概是这样的:
return score == 100 ? "Perfect" : "Not Perfect";
但是,在Python语言中,是这样的:
return "Perfect" if score == 100 else "Not Perfect"
显然,三目运算符比if-else的形式更简洁,但是在逻辑表意上,更加复杂,不够直观。而Python的写法,更接近自然语言,任何人,即使没有计算机背景,也能一眼看懂这句话的意思。所以,三目运算符被Python直接摒弃了。类似的,++, --这类所谓更“简洁”的语法,也被Python摒弃了,也是这个原因。
这类语法的弃用,绝不仅仅是Python一门语言的选择,比如苹果几年前刚发布的新语言Swift,也是如此。编程语言的发展趋势之一,就是越来越向着给人看的方向发展,而不是给机器看。
2. 去除和逻辑无关的语法
编程语言的另一个发展趋势,就是摒弃和业务逻辑无关的语法规则。最典型的例子,就是现代大多数语言都不再有显示声明指针的语法。
相信对于大多数同学,如果学习过C或者C++语言,在学习int*, int**, int&, 等等这些语法规则的时候,都是一团浆糊。甚至可能很多同学毕了业,都没有特别搞清楚C/C++语言中的指针和引用到底是怎么回事。
相信对于绝大多数同学(至少对于我是如此),在刚接触C语言的时候,连使用scanf,都是一场噩梦。
int a;
scanf("%d", &a);
// 我们先不提%d是怎么回事,a前面为什么一定要有个&????
// 但是,如果a是一个char[]的话...
char s[80];
scanf("%s", s);
// 咦?怎么s前又不需要&了?
这段代码中,这个&(C/C++中是地址符),就是和业务逻辑无关的语法规则。在这里,我不详细的介绍C/C++中的这个语法规则了。其实,如果你不使用C/C++,对于现代编程语言,你完全不需要理解这其中有什么区别,在什么时候应该使用哪个语法。
相较而言,比如Java语言的控制台输入,是使用Scanner类,写出来大概是这样的。
Scanner myScanner = new Scanner(System.in);
int a = myScanner.nextInt();
String s = myScanner.nextLine();
同样,对于C++语言,写出来大概是这样的:
int a;
cin >> a;
string s;
cin >> s;
虽然,对于Java和C++的IO部分的语法设计(或者说类设计),还是有很多吐槽和更好的建议,但是,很明显的,高级语言在努力摒弃掉诸如%d, %s, &, 等等语法规则。因为,这些语法规则和具体逻辑无关。
对于指针这个概念同理。对于大多数高级语言,和指针相关的语法都被隐藏起来了。当然,现阶段,对于程序员,还是必须要理解清楚指针这个概念的(在Java,Python等语言中,其实就是引用)。但是,从语法的角度,这个概念“消失”了。这显然对初学者更友好。初学者不需要纠结,什么时候用*,什么时候用&。语言的使用者,将更多地精力,集中在逻辑表达上,而非语法细节上。
3. 自动垃圾回收
说到剔除逻辑无关的规则,最为典型的,就是现代语言在大多数情况下,不再需要程序编写者处理垃圾回收相关的逻辑了。很多语言,即使本来需要手动处理垃圾回收逻辑,在版本升级的过程中,也改为了自动垃圾回收机制。这也是因为,垃圾回收是和我们要表达的逻辑无关的,是关于机器怎么执行逻辑的。这里,最典型的例子,就是OC语言。
我是iOS 4的时代开始接触iOS开发的。那个时候,OC语言是需要进行手动垃圾回收的(和C/C++语言一样)。但是从iOS 5开始,OC语言引入了自动垃圾回收机制,被称为ARC。虽然严格意义上,ARC和Java的GC还不一样(这是因为这两种语言本身的内存管理模型有所不同),但是他们的目的都是相同的:让程序员更多的专注于业务逻辑代码的编写,而不是诸如垃圾回收这样的只有机器才关注的问题上。如果你尝试使用过需要手动处理垃圾回收机制的语言编写较大的项目,如C/C++/OC,就会明白:你很有可能会花费50%的时间,来保证整个系统的垃圾回收是没有问题的。但是,使用“现代”编程语言,这些时间都可以用来精进你所要实际表达的代码逻辑。
对于现代编程语言,自动垃圾回收机制,近乎是标配。这也使得,越来越多的程序员,根本不了解内存管理,也不需要了解内存管理,就可以胜任大多数工作。在这方面,我一直喜欢举发生在我身边的一个iOS程序员的例子。我的这位朋友,文科生出身,在iOS 5的时代开始接触iOS开发。他接触iOS开发,完全是因为在那个时代对于苹果产品的疯狂着迷,爱屋及乌,也想要开发属于自己的iOS App。结果,竟然在那个大多数程序员都还不太接触iOS开发的年代,无意中转行进入了IT行业,并且抓住了风口,在短短一年的时间里,成为了国内某著名品牌的iOS事业部负责人。在那个年代,大多数硕士毕业的研究生,在大厂的工资,也就是10万每年。他一个文科生,本科学历转行进计算机,借助iOS开发的契机,竟在那时就达到了30万每年的薪水。
对于这个案例,除了佩服他的兴趣,感叹时代和机遇的力量,以及佩服他的执着和努力之外,我也常常想:或许,这和OC语言本身在iOS 5开始,开发者不再需要处理内存管理,也是分不开的。否则,对于文科生来说,理解内存管理,学习曲线真的太陡峭了。
苹果每年都会在自己的发布会上声称,iOS开发生态中,有多么多么小的开发者,或者多么多么老的开发者。是因为突然这个年代的人们都是天才了吗?不是。因为开发真的越来越简单。
九岁的苹果开发者 Anvitha Vijay
4. DSL
上面举的例子,不论是分号,大括号,三目运算符,指针,地址符,垃圾回收,等等等等,这些功能在编程语言中的演化,本质,其实都是:编程语言在逐渐剔除和业务逻辑无关的语法,从而让开发者更多的关注在业务逻辑自身上,而不是机器怎么执行这些逻辑上。简单的总结,可以理解成:现代语言的发展趋势是:编程的主要任务越来越多的是告诉机器要做什么(what),而不是怎么做(how)。
正是因为这个方向的指引,越来越多的DSL语言被发展出来。
DSL,是Domain Specific Language的缩写,翻译成中文,就是“特定领域语言”。其实,对于DSL语言,我们都不陌生,最典型的DSL,就是SQL。大家体会一下下面的这段SQL代码:
SELECT name FROM Student WHERE score = 100
大家想想,这段代码所表示的逻辑,用其他语言怎么写?在大多数语言中,大概是这样的:(伪码)
names = []
for student in students:
if student.score == 100:
names.append(student.name)
return names
看了这两段代码,不知道大家是不是能够理解,什么叫告诉机器what,而不是how。对于SQL语言来说,我们的代码近乎就是用自然语言说:我们要把分数是100分的学生姓名拿出来;而对于其他大多数语言(C++, Java等等),我们还需要循环(for),需要条件判断(if),需要考虑拿回来的学生姓名怎么存储(数组?集合?),还要手动把一个一个符合条件的学生姓名添加进去(append)。显然,这段代码更多的涉及how,而不仅仅是what。
当然了,SQL语言这种“简洁性”是有代价的,这个代价就是DSL中所谓的Domain Specific, 即领域相关。使用SQL,我们只能处理和数据存储相关的内容(通常所说的增添改查),但是,我们不能用SQL做移动app,不能用SQL做后端业务逻辑,不能用SQL做前端,也不能用SQL做动画,做游戏,做人工智能。但是,只要是和存储相关的东西,掌握SQL这么一个简单的工具就够了。
DSL还有很多,在现代的环境下,近乎每一个程序员都一定会接触那么几个DSL。再比如说,正则表达式也是一种DSL,正则表达式只可以进行模式匹配。但是,对于模式匹配,再复杂,使用正则表达式解决,也比自己写模式匹配算法或者模式匹配工具要强。
HTML和CSS也属于DSL,虽然,这两种语言本质上处理的不是逻辑(CSS越来越强大,也已经有了“逻辑引擎”),但是,如果学习过HTML和CSS的同学一定了解,这两种语言都是上手极快的(当然,上手和精通是两回事儿)。我们可以很快的就使用这两种语言来做出页面,而且,看上去还不错。这就是DSL的意义——可以更快地,更简洁地,去让哪怕是“计算机科学的外行”,用编程的方式,去做特定领域的事情,而不用去纠结过多“计算机科学”相关的内容。
在这个年代,做科研工作,近乎一定要编程,并且,大多数科研相关的编程工作,是和数据相关的。因为各个领域的前沿研究,都需要在领域相关的大量数据中,寻找新的突破和发现。可能有很多同学知道,Python和R是现今最主流的两种用于数据处理的语言。如果你身边有非计算机领域的博士同学,或者研究工作者,去问问他们。你会惊讶的发现,大多数非计算机专业的研究工作者,更常用R语言,而非Python语言。为什么?因为,相较Python语言,R语言更像一个DSL。当然,R语言本身也很强大,但是远没有Python强大。R语言本身近乎就是为数据科学设计的语言,大多数数据科学所需要的功能,R语言或者本身从语法层面支持,或者在标准库中内置好了。所以,对于非计算机专业的人士而言,R语言是更加友好,上手更快的。使用R语言,可以尽量少的去接触和“计算机科学”相关的知识,就能上手复杂的数据处理任务。
相较于SQL,正则表达式,CSS,HTML,R等等这些DSL,计算机专业的同学通常需要努力学习的,诸如C++, Java, Python等语言,被称为GPPL。是General Purpose Programming Language的简称。也就是所谓的“通用目标语言”。顾名思义,通用目标语言没有把功能限制在特定领域中,相较DSL更灵活,可以完成更多的事情,甚至可以说是任意逻辑(嗯,这句话细究起来,又可以写一篇新文章了),但代价就是:语言本身操作起来更灵活,也更复杂。
整体而言,越来越多的DSL的出现,也是编程语言发展的一大趋势。比如,在现在大火的人工智能界,很多人就认为,使用现有的语言做人工智能算法,太麻烦了。人工智能专家要花很多时间,来处理和人工智能算法无关的逻辑上。发明一个人工智能领域专有的DSL,近乎是必然。很有可能,我们在未来,还将看到医学领域特定的DSL,生物学领域特定的DSL,化工领域特定的DSL,物理学领域特定的DSL,等等等等。
另一方面,在未来,使用GPPL的工程师们——也就是真正计算机专业的同学们,一个很重要的任务,就是开发DSL。开发出的这些DSL,是给其他领域的专家,或者业务专员使用的。还记得我在《学算法有什么用?唉,对你来说,可能真没用》所说的吗?“分工”本身就是经济学的基础概念之一,是我们这个世界能够良性运转逐渐发展的诸多核心规则之一。这种GPPL和DSL越来越清晰的分层,也是“分工”这一经济学概念在编程语言界的体现:)
当然,对于GPPL,也有很多发展趋势。比如动态性,比如对函数式编程的支持,比如对并发的支持,等等等等。有机会,我再向大家总结:)
对于计算机专业的同学来说,语言只是一种工具而已。学习语言的目的,不是对细微的语言特性和语法糖如数家珍,关键还是要应用语言,解决实际的场景问题。
很多同学会问,十年后,什么语言最火?很有可能,十年后最火的语言,现在还没出现呢:)
大家加油!:)
本文相关阅读推荐:
学算法有什么用?唉,对你来说,可能真没用
《是不是很酷》虽然只是一个个人公众号,但在用心做技术原创。不随便追捧热点,不故弄玄虚,客观地发表有质量的观点,力争用外行人都能看懂的语言,说内行人关注的事儿。
本公众号每周至少一更,争取双更,虽然不能保证每天更新,但作者保证每篇文章都是用心的。希望一起陪你,用技术人的眼光,观察这个世界,探索这个世界。
如果你喜欢我的文章,愿意支持我继续写下去,希望能够关注我的公众号,转发我的文章,或者为我点赞。读者的鼓励,是每一名作者继续坚持下去的唯一动力:)