Pulpcode

捕获,搅碎,拼接,吞咽

0%

强弱类型到底是个啥?

程序员们喜欢撕逼,他们会争论vim和emacs那个才是最牛逼的编辑器,会比较linux和Windows哪个更牛逼些,还会比较java和c#哪个更强大一些,因为他们总喜欢追寻自己的教条和信仰,跟别的队伍吵个不停。最近总听见有人在讨论关于编程语言的强弱类型,他们常常为某种语言是不是弱类型吵得不可开交。jser,PHPer们可能是因为被黑惯了,他们一般表现出”你说啥都行,弱类型就弱类型,无所谓,你们开心就好的心态。”但是pythoner不这么想,作为一个向往逼格的pythoner,如果有一个javaer跟他说:“python是弱类型,java是强类型”,那他一定会跟他争论个面红耳赤,再跟他讲“强类型,弱类型,静态语言,动态语言之间的区别与联系”。我原来就是这样的一个pythoner。但是最近我突然想起来大四的一节软件工程课上,老师谈到从第一代编程语言到第五代编程语言的区别,我发现分类方式和我在图书馆读到的不一样,所以我下课之后还去找他讨论了一番,但老师只是很平静的对我说,其实这个定义只是一个简单的分类说法,没什么严格标准的定义说某种语言就是第三代语言。这个经历让我突然想问自己,“我们在天天撕的强弱类型,它到底是个啥?”

大众的现状

目前而言,大部分人眼中c,java,C#这样的语言就被称为强类型语言,而php,js,python就被称为弱类型,因为他们认为像java这样的语言,任何一个变量在声明的时候,都要明确指定其类型,比如像这样:

1
StringBuilder sb = new StringBuilder("SB!");

而python并不用在声明的时候,给它定义一个类型:

1
s = "123"

而且python的变量貌似看上去还可以随便赋值

1
2
i = 1
i = "123"

所以他们就认为python是弱类型。

这是普遍的观点,但是这个没什么说服力。我举个例子,按照这个说法,java和c#都是强类型语言,但是c#有一个“自动类型推倒”的功能,(不知道java现在有没有这个功能,就算现在没有,将来也会有的,因为java最爱抄c#)。

1
var s = “abcd”;

var是C#的语法糖,它让编译器自动推倒类型,这是在C# 3.0开始新增的特性,需要说明的是这个变量必须是局部变量,而且必须在一开始就初始化,而且这个变量就是字符串类型,并不能被赋值成其它类型。看这就没有声明类型,那么你能因为一个语法糖就把c#从强类型变成弱类型?

稍高一点

比前面这种看法认知高一点的,会说上面那个不同,不是强弱类型的区别,而是动态语言和静态语言的区别,因为静态语言需要在编译期间做静态类型检查,所以必须要声明类型,而python是动态语言,类型在运行时才确定(python也会编译成一种机器码,为了在虚拟机上运行,但是没有类型检查的阶段),所以不需要声明。

然后他们会说,所谓强弱类型其实是类型之间的操作有无明确规范,比如在php和javascript中,你可以这样写:

1
$b= 2 + "3.14";  

看,你把一个整数和字符串相加了,但是在python中和java中不能,所以php是弱类型,而java和python是强类型。

实际上pythoner完全可以先自黑一把:

1
4 > "1"

这条语句在python中不会报错,而且还会返回False,实际上更有趣的是,python中任何两个对象都可以比较大小,这里有具体的大小比较规则:5. Built-in Types

那么pythoner们如何定义,类型之间的操作明确规范?(以上是python2.x的特性,在python3.x中,整型和字符串比较会抛异常)

javaer们也别走,你们的类型之间的操作明确规范呢?:

1
System.out.print(123 +"456");

类型转化

有部分人讨论强弱类型是根据类型转换的,就因为这点,会把c和c++归为弱类型语言,因为c++要兼容C,所以我们直接讨论C语言。因为c语言是一个比较老的语言,而且偏于底层(可以直接操作内存),所以类型转换和指针满天飞,而且人家的强制类型转换简直万能,比如你可以这样:

1
2
3
struct A a;
struct B b;
b = *(struct A*)&a;

类型转换配上万能指针-void指针,“简直完美”(任何指针都可以转换为void指针,void指针也可以转化为任何指针)

1
2
long* a = &b;
double c = *(double*)((void*)a);

c语言当然有类型检查了,但是它可以绕过类型系统,这真是因为C语言本身所带有的工业属性,C语言一开始设计是为了写UNIX的好么,写操作系统的语言没有指针和类型转换的C语言还怎么玩,你去看看linux标准C库的list,居然是个多态链表,面向过程的语言怎么实现的?还不是靠void指针和强制类型转换还有宏。所以不能因为这个就说人家是弱类型。

定义源头

之后我去找了到底这些强弱类型的定义出自哪里,国内的网站已经满足不了我了,是时候去stackoverflow和wiki上看看了。

实际上,国外有很多人对于弱类型的定义都是:

Strong/Weak typing is about how strictly types are distinguished (e.g. whether the language tries to do implicit conversion from strings to numbers).

你会发现这个定义很模糊,就像我们之前讨论的,每种语言都有弱的方式和弱的理由。

stackoverflow还是有人提出了这个观点:“关于语言的强弱类型过于模糊,讨论起来没有意义。”

Probably the most common way type systems are classified is “strong” or “weak.” This is unfortunate, since these words have nearly no meaning at all. It is, to a limited extent, possible to compare two languages with very similar type systems, and designate one as having the stronger of those two systems. Beyond that, the words mean nothing at all.”

You have discovered a soft spot in the terminology that amateurs use to talk about programming languages. Don’t use the terms “strong” and “weak” typing, because they don’t have a universally agreed on technical meaning. By contrast, static typing means that programs are checked before being executed, and a program might be rejected before it starts. Dynamic typing means that the types of values are checked during execution, and a poorly typed operation might cause the program to halt or otherwise signal an error at run time. A primary reason for static typing is to rule out programs that might have such “dynamic type errors”.

在wiki百科上,也有类似的说法:Type_system

red to as “strongly typed” or “weakly typed”. In fact, there is no universally accepted definition of what these terms mean. In general, there are more precise terms to represent the differences between type systems that lead people to call them “strong” or “weak”.

而且还引出另一个概念:Explicit/Implicit(显/隐类型),这个我们提到过,也容易被当成强弱类型的区别,一般像C,JAVA这样的语言,是需要声明自己类型的,但是Haskell这样的却不用声明,因为它有自动类型推倒,而且我敢说要真比较类型强弱,haskell要比很多静态语言强类型的多,我只学过一点点haskell,但我知道haskell的一个变量定义成什么就是什么了,连再赋值都不行。毕竟函数式编程语言,或者说这都不能被称为变量了。

所以以后再有人讨论关于“java,python强弱类型”的时候,我都会保持沉默,无视他们,心里默默的想,“java,python, ruby哪个才能被算作是纯面向对象的语言”。。。。