编程语言的基础核心来自于逻辑,来自PROGRAMMING LANGUAGES & TYPE SYSTEMS文章从罗素悖论角度解释,为什么我们引入类型系统,然后才有了今天的编程语言,这对深入理解编程语言来源,破除语言误区有很大帮助。
著名的罗素悖论是:一个集合到底包含不包含它自己?
举个例子,如下集合a包含a本身:
a = { a, b }
但是,我们常识中对树形结构的了解,一个节点(枝)是由其他节点组成的(左 右或子),但肯定不是由它自己组成的,因此我们又认为集合a不应该包含a本身:
a={任何除了a的元素}
或a={b}
我们总结下面:
1.集合包含他们自己
2.集合不包含他们自己
如果有很多集合,这些很多集合也可以表现为一个大集合,那么我们得到如下描述:
1.所有集合的集合应该包含他们自己。
2.所有集合的集合不应该包含他们自己。
从前面推论我们已经知道,我们倾向于第二条为真,但是注意第二句就发生了逻辑矛盾,如果我们需要统计不包含自己的所有集合,必须首先统计其主集合,因为主集合实际上是包含了所有集合的,但是主集合也是一种集合,而集合是不应该包含他们自己的,结果这里发生矛盾,这就是著名的罗素悖论。
解决罗素悖论是引入类型理论(http://en.wikipedia.org/wiki/Type_theory),引入不同类型的层次,每个层次结构中的层只是由同一类型中先前层次组成的。这就诞生了我们今天现代语言Java, C#, Ruby, Haskell 等等,都是采取类型理论,实现特定的属性和层次。
知道这种来历,对于理解编程语言中动态类型(Ruby)和静态类型(Java Scala)等区别很有帮助,还有一种强类型和弱类型,比如Java如下:
// Given a method:
public void increment(int i);
// This call is illegal
increment(24.0);
增加这个方法是非法的,因为24.0是一种double类型,而方法函数参数类型要求是int,Java并不知道如何将24.0转换成int类型,但是也不鼓励由Java自动实现,因为Double在Java中是64位,而int是32位,进行自动转换会丢失信息。
但是Java允许 3+24.0这种算法,这是一种类型扩展type-widening表达用法,算式的结果类型是double的,整数int能够被保护,这种转换将被允许,但是int x = 3+24.0又不允许。
在动态类型语言Python中"1"+2 结果是错误的:
TypeError: cannot concatenate 'str' and 'int' objects
告诉我们范了一个类型错误,Python并不知道如何转换这些类型,同样Ruby会报类似错误,这其实是一种强类型影响的表现,它存在在静态类型语言Java C#,也存在动态类型语言Ruby Python Scheme中。
为了纠正这种错误,我们必须显式地进行转换,如Python必须如下:
"1" + str(2) # returns '12'
或者:
int("1") + 2 # returns 3
很显然Python并不确定"+"(加号)这个操作符应当将字符转为整数型,它留给程序员解决,这是强类型系统中一个最佳实践。
在java中下面是允许的:
"1" + 2 // returns "12"
这里"+"加号操作符被认为是调用对象的.toString(),这是值得商榷的选择,但是它增强了灵活性。
在Python中,一个函数能够接受任何类型的对象:
def fun(arg):
...
这比报类型错误要更加安全,相反Java支持强制性类型:
void fun(String arg) { .. }
这是一种更加安全的方式,只接受特定类型参数。
大部分动态类型语言都假设任何对象能够被转换成String,这是一种为了方便而实现的妥协。
下面谈谈弱类型,javascript是一种弱类型语言:
"100" > 10 // returns true
和上面谈到的强类型不同的是,弱类型语言定义了一些基本约束,防止程序员射中自己的脚,这些类型的自动转换是语言的特别之处,但是每个语言也有自己在遭遇矛盾类型情况下的解决方式:
100 + "1" + 0
结果将是"10010",而在VB,将是数字101,这种转换虽然带来方便,但是也有一定随意性,这时强类型语言显示出其特有的可预测的逻辑一致性了。
结论:
强类型Ruby和java对于团队开发更加安全,而弱类型则可提供快速基于浏览器内部的开发 。