这本书是一位日本人写的,装订得蛮漂亮。因为白骨精学习法一书,我对日本人诡异的思路相当感兴趣,日本人写的书有种不一样的风味,在某一方面上有很大的参考价值,所以第一眼看到这本书的时候就感兴趣了。
##语言为什么会这样设计
本书主要从语言的发展史,穿插地介绍一些语言背后的东西。
关于条件判断语句
if…else,while,break,相对于以前的语言来说,也就是加了限制的 goto 语句。
关于 while,与 for: 一开始是先设计出 while 语句的,但对在0至N范围的某种数值进行某种操作,这样的需求经常会遇到。
i = 0; while(i<N){ printf(“%d ”,i); i++; }
用 while 语句实现起来是这样的,在循环体外写 i=0 ,循环条件写 i<N, 循环体写 i++。代码分散,这样原来要表达的意图就会别削弱,因为这是经常用到的。所以就有了跟while功能类似的for语句。
关于函数
在最初程序中,命令和数据完全都存储在内存中,修改程序就如同把数值代入变量中一样简单。通过修改程序中跳转目的地,就能使函数调用后返回原来的位置。
不过这就要求程序员知道函数跳转的目的地地址,以及返回原来的内存地址。这是很难办到的,因为如果在函数中增加几行代码,返回命令的位置就会相应地往后挪一些。这样一来,就不得不修改调用这一函数的全部代码。
后来有改良的办法:创建用来事先记录返回目的地的内存空间,并设计能跳转到该内存空间里记录的地址的命令。这样,即使函数调用前不知道返回命令所在地也没关系。但是这又有一个问题当调用函数X期间又调用了Y函数时,返回的目的地内存被覆盖,函数X执行后应该返回的目的地址就找不到了。
再后来,就轮到栈登场了。栈就是用来存储函数的返回的目的地地址等信息。
关于异常处理
一开始语言的错误处理大体可以分为两种:一种是利用函数返回值来传达错误信息(比如C传-1来表示错误),另一种是在调用函数前设定好错误处理的代码,错误发生时能跳转到相应的错误处理代码。
在错误就跳转处理这种主导思想下也出现过几种设计:
l PL/I语言,先定义好出错时的错误处理操作,再编写可能出错的代码。
l Java等,先编写可能出错的代码(try{}),然后编写出错时的处理操作。
相应的,在这种设计下也带来了一些问题。在捕获到错误后,有些必须要执行的操作会被忽略,所以微软引入了finally语句。
关于异常,不同的设计者又持有不同的观点。比如对于数组越界的问题,Python会抛出异常,Ruby会返回一个指示不存在的特殊值(nil),而JavaScript会返回undefined。而调用有两个参数函数时,只传递了一个参数时,Python和Ruby会在函数调用的时候抛出异常。但JavaScript会把缺失的参数当做未定义的特殊值(undefined)继续执行。(orz 这样看来JavaScript真是很多坑…)
这三门语言的设计者都是大牛中的大牛,他们对于何种情况应该抛出异常也不能达成一致。异常应该在何种情况下使用,何为异常的情况,这些问题是没有正确的答案的。
PS:当然出错后立即抛出异常一般来说是比较好的习惯。
异常的传递:
在Java语言在内的很多现代语言的异常处理机制中,异常可传递至调用方。也就是说,如果函数f调用g,g调用h。h有异常抛出,但无法或没处理异常,那么就会看函数g能否处理异常,再不行就传到f。
关于这个设计,大家意见并未统一,因为这个设计有一个很大的问题。那就是,即使看到了f函数的代码也不知道函数f可能会抛出什么异常,有可能是g会抛出,也有可能是h会抛出。换句话说,也就是不看见f调用的所有函数的代码是无从得知f会抛出何种异常的。
1975,John Goodenough在自己的论文中主张为了避免这一问题,需要明确地声明可能会抛出的异常。其中Java语言就采用了这个方针。
Java对异常进一步分为三类:不应该做异常处理的重大问题、可做异常处理的运行时异常和做异常处理的其他异常。其他异常叫做检查型异常(也就是玩家自己定义的),如果在方法之外熬出,就需要在定义方法时声明。Throw就是为这个目的而准备的。
检查型异常时一种非常好的机制,但是并没有很好地普及到其他语言中。一言蔽之,就是他太麻烦,一旦throws或try/catch中异常数目增多,或者某一方法需要追加一种异常,就不得不修改调用了该方法的所有方法,特别麻烦。
C#很大程度上参考了Java,但没有借用它的这种机制。C#设计者Anders Hejlsberg说:“检查型异常的理念本身并没有什么不对的地方,相反是很棒的。然而在像Java语言这样的实现方式下,它在解决某些问题的同时又引入了别的问题。如果能有更好的实现方法,C#语言或许也是可以借用的”
PS:作者在写这章时,插入了一段话,关于阅读作者本人写的文档而不是二手资料时的策略问题。他采用三种策略:一从需要的地方开始阅读,二先掌握概要再阅读细节,三从头开始逐章手抄。我用的最多的就是第一种了。其实也并不是十分有用的建议哈哈。
关于命名以及作用域
待补充