无论因为什么,你可能想要自己造一个语言。在具体实施之前,请听我一些忠告。
首先开发语言是一个一非常漫长又辛苦的过程,现在很多成功的语言都是由一个大公司的团队经过几年的打造才完成的,如果你不能保证长期的投入,建议还是放弃这个念头,以免前功尽弃。
其次,你得明确你的语言的亮点是什么。除非你的亮点足以使用户可以这个接受学习新语言的成本,否则它很难会被用户接受。但这很困难。你可能觉得你现在用的语言能用,但总有那么几个不爽的地方,所以你决定造一门自己的语言,至少在某些地方比其他语言要好用,要牛逼。然而光几个细微的改进是远远不够的,就像谁都知道核桃难剥,但还是会买来吃一样,不是说你做了一个已经剥好壳的核桃仁,就会比那些没剥壳的核桃好卖。
编程语言的用户是程序员,而绝大多数的程序员都是负责“搬砖”的,他们选择一个编程语言,不是因为这门语言有多好用,只是单纯地因为这门语言能让他找到工作,所以如果你创造一个没有人用的新语言,即使这门语言你真的做的很好,也不会有人对它感兴趣,更何况新语言实际并没有你所说的那么好。
怎么算开发编程语言
如果你以为做一个新语言的 parser 就算完成一个新语言了,那你太弱了。
一个完整的语言,需要有编译器,需要有 IDE 支持,需要有完整的标准库,还需要有适用的场景以及配套的工具。单纯的 parser 只占了整体工作的 5% 不到。
你可能会说,我就做个 parser,然后翻译成别的语言,这确实能节省不少的工作,但 IDE 支持呢,还有调试怎么办?如果这些不解决好,你会发现,用新语言的开发成本还不如用以前的。
大括号还是缩进式
总有那么几个人很讨厌 Shift 键,输入一对大括号加回车缩进要按键6次,而采用缩进式语法,可以少敲4次,特别是在终端里面打代码的时候,缩进式语法要爽不爽,所以那些不怎么打代码的,一些电脑爱好者,或者是运维、黑客,更偏向于缩进式语法。
但缩进式语法也有几个缺点让专业程序员讨厌,首先是缩进式的语法在视觉上,层次没有大括号清晰,如果编辑器没有缩进线,代码又很长,那更恐怖了。其次,要从别的地方抄一段代码,大括号可以一键格式化还不出错,而缩进式的就要头疼了,对于经常抄代码的码农来说,这是最不能忍的。最后,如果告诉你,你的 BUG 是因为代码中的几个空格导致的,你可能会抓狂。
强类型还是弱类型
无论怎样的语言都会有变量,变量的类型是否可变,决定了整个语言的基调。从实践角度,手动标注类型,有利于项目的长期发展,但短期成本较高,而无需标注类型的脚本语言,短期成本低,但项目变大后,维护成本会突然上升。所以现在新语言的趋势,是强弱类型混合,再辅以类型推导,这样短期弱类型为主,等到项目变大后,逐步调整为强类型。
关键字要多还是少
有一批人认为,语言应该做的尽量简洁,关键字要尽量少,最好是没有,一切都是函数,包括 if。
也有一批人认为,关键词越多,说明语言的功能越多,只有功能强大语言才好用。
此外还有一批吃瓜群众说:你就做的和现在语言做的一模一样就可以了,语法多了看不懂,语法少了不够用。
其实每个人的立场不同,就像你和大爷说人艰不拆他可能听不懂,但如果你正式地说“请不要拆穿我们”,好像也怪怪的。有一些语法,能懂的人觉得是便利,不能懂的人觉得是天书。选择用一个既有的语法组合,以盲目创造新的语法,要优秀很多。
代码不是越短越好(不然你读读文字超短的文言文看看?),代码写的越短,意味着读者要猜的越多。优秀的语言往往是用一句短但不产生歧义的代码,完成尽可能多的事情。
有 while 还需不需要 do..while
do..while 和 while 类似,只不过多执行一次循环,很多搬砖的按亲身体验说:“do..while 是个啥,从没用过。”
所有的 do..while,都可以写成 while,但且没有增加多少代码量,也没有降低可读性。
比如
do { 执行操作() } while(!操作是否成功())
可以写成:
while(true) { 执行操作() if (操作是否成功()) { break } }
而且实际业务中的场景,多数是这样的:
while(true) { 执行操作() if (操作是否成功()) { break } 执行初始化() }
所以 do..while 的场景更少了。
如果不考虑和现有语言的兼容性和用户习惯,去掉没什么影响。
switch 要不要允许自动穿越 case
很多代码检测工具都会检测 switch 是否丢失了 break,从实践角度,忘写 break 是一个经常犯的错,所以从源头堵截错误,看样子是有用的。
很多新语言也确实这么做了。但还是有一些场景,需要穿越 case,比如两个 case 共用一个逻辑。
引入逗号隔开的表达式可能是一个方案:
switch (x) { case 1, 2, 3: // ... case 4, 5, 6: // ... }
这个方案缺点是两个 case 的逻辑要不全共用,要不全不共用,更好一点的做法是像 GO 语言一样引入关键字:
switch (x) { case 1: fallthrough case 2: // ... }
或者改变 continue 的含义,使得 switch 中的 continue 用来继续下个 case:
switch (x) { case 1: continue case 2: // ... }
要不要有 null
有很多人说 null 是个糟糕的设计,我们应该拒绝 null,但那依然存在于很多语言之中,最主要的原因是性能。
现在语言的趋势是,提供 null,但也配备了完整的 null 检测工具,比如 ??, ?. 运算符
= 只能是语句还是允许表达式
如果 = 作为语句,可能会把判断中的 == 误写成 =。
有的人还会说,= 作为独立的一行语句,可以更清晰地知道,变量的值在什么时候被修改了,除非删除闭包函数内覆盖外部变量的功能,否则变量的值仍然可能在一个没有 = 的表达式中被修改。
将变量的定义和使用尽量放在一起,有助于提高代码的可读性,甚至还有人建议在 if 里直接声明变量:
if (var x = foo()){ x.abc // x 不是 null }
这都说明了,允许将 = 放在表达式任意位置,可以简化代码,提高可读性。
Python 不允许等号出现在表达式,因为表达式中的 = 表示了函数参数名。
要不要支持Unicode字符作为变量名,全部还是部分?
支持变量名中文?废话,不多说!但,支持所有非ASCII字符作为变量名怎么样?不行,因为:
1. 代码会不容易查错,因为个别字符是不可见的。
2. 可能存在安全问题,比如将不良代码伪装成不可见字符。
3. 并不是所有的编辑器、终端完整支持所有 Unicode。
=====待补充======
?好你在干什么