语言表达能力欠缺的改进方法 强类型语言和弱类型语言哪个好

前言我在上一篇文章中分析了 为什么 Python 没有 void 类型 的话题,在文章发布后,有读者跟我讨论起了另一个关于类型的问题,但是,我们很快就出现了重大分歧 。
我们主要的分歧就在于:Python 到底是不是强类型语言? 我认为是,而他认为不是 。
他写了一篇很长的文章《谁告诉的你们Python是强类型语言!站出来 , 保证不打你!》,专门重申了他的观点,但可惜错漏百出 。
我曾有想法要写写关于 Python 类型的问题,现在借着这个机会 , 就来系统地梳理一下吧 。
(PS:在我写作进行到差不多一半的时候,微信读者群里恰好也讨论到“强弱类型”的话题!在与大家讨论时,我的一些想法得到了验证 , 同时我也学到了很多新知识,所以本文的部分内容有群友们的功劳 , 特此鸣谢?。?
1、动静类型与强弱类型很多读者应该都熟悉动态类型 与静态类型 ,但是很多人也会把它们跟强弱类型 混为一谈,所以我们有必要先作一下概念上的澄清 。
这两组类型都是针对于编程语言而言的,但关注的核心问题不同 。
对于“动静类型”概念,它的核心问题是“什么时候知道一个变量是哪种类型”?
一般而言,在编译期就确定变量类型的是静态类型语言 , 在运行期才确定变量类型的则是动态类型语言 。
例如 , 某些语言中定义函数“int func(int a){…}”,在编译时就能确定知道它的参数和返回值是 int 类型,所以是静态类型;而典型如 Python,定义函数时写“def func(a):…”,并不知道参数和返回值的类型,只有到运行时调用函数,才最终确定参数和返回值的类型,所以是动态类型
对于“强弱类型”概念,它的核心问题是“不同类型的变量是否允许隐式转化”?
一般而言 , 编译器有很少(合理)隐式类型转化的是强类型语言,有较多(过分)隐式类型转化的是弱类型语言 。
例如,Javascript 中的 “1000”+1 会得到字符串“10001”,而 “1000”-1 则会得到数字 999,也就是说 , 编译器根据使用场合,对两种不同类型的对象分别做了隐式的类型转化,但是相似的写法 , 在强类型语言中则会报类型出错 。(数字与字符串的转化属于过分的转化,下文会再提到一些合理的转化 。)
按照以上的定义,有人将常见的编程语言画了一张分类图:

语言表达能力欠缺的改进方法 强类型语言和弱类型语言哪个好

文章插图
文章插图
按强弱类型维度的划分,可以归纳出:
  • 强类型:Java、C#、Python、Ruby、Erlang(再加GO、Rust)……
  • 弱类型:C、C++、Javascript、Perl、PHP、VB……
2、过去的强弱类型概念动静类型的概念基本上被大家所认可,然而,强弱类型的概念在问答社区、技术论坛和学术讨论上却有很多的争议 。此处就不作罗列了 。
为什么会有那么多争议呢?
最主要的原因之一是有人把它与动静类型混用了 。
最明显的一个例子就是 Guido van Rossum 在 2003 年参加的一个访谈,它的话题恰好是关于强弱类型的(Strong versus Weak Typing):
语言表达能力欠缺的改进方法 强类型语言和弱类型语言哪个好

文章插图
文章插图
但是,他们谈论的明显只是动静类型的区别 。
访谈中还引述了 Java 之父 James Gosling 的话 , 从他的表述中也能看出 , 他说的“强弱类型”其实也是动静类型的区分 。
另外还有一个经典的例子,C 语言之父 Dennis Ritchie 曾经说 C 语言是一种“强类型但是弱检查”的语言 。如果对照成前文的定义,那他其实指的是“静态类型弱类型” 。
为什么这些大佬们会有混淆呢?
其实原因也很简单,那就是在当时还没有明确的动静类型与强弱类型的概念之分!或者说,那时候的强弱类型指的就是动静类型 。
维基百科上给出了 1970 年代对强类型的定义,基本可以还原成前文提到的静态类型:
In 1974, Liskov and Zilles defined a strongly-typed language as one in which “whenever an object is passed from a calling function to a called function, its type must be compatible with the type declared in the called function.”[3] In 1977, Jackson wrote, “In a strongly typed language each data area will have a distinct type and each process will state its communication requirements in terms of these types.”[4]
前面几位编程语言之父应该就是持有类似的观念 。
不过,大佬们也意识到了当时的“强弱类型”概念并不充分准确,所以 Dennis Ritchie 才会说成“强类型但是弱检查” , 而且在访谈中 , Guido 也特别强调了 Python 不应该被称为弱类型 , 而应该说是运行时类型(runtime typing)。
但是在那个早期年代 , 基本上强弱类型就等同于动静类型 , 而这样的想法至今仍在影响着很多人 。
3、现在的强弱类型概念早期对于编程语言的分类其实是混杂了动静与强弱两个维度 , 但是,它们并不是一一对应重合的关系,并不足以表达编程语言间的区别,因此就需要有更为明确/丰富的定义 。
有人提出了“type safety”、“memory safety”等区分维度 , 也出现了静态检查类型和动态检查类型 , 与强弱类型存在一定的交集 。
直到出现 2004 年的一篇集大成的学术论文《Type Systems》(出自微软研究院,作者 Luca Cardelli),专门研究编程语言的不同类型系统:
语言表达能力欠缺的改进方法 强类型语言和弱类型语言哪个好

文章插图
文章插图
论文中对于强弱检查(也即强弱类型)有一个简短的归纳如下:
  • Strongly checked language: A language where no forbidden errors can occur at run time (depending on the definition of forbidden error).
  • Weakly checked language: A language that is statically checked but provides no clear guarantee of absence of execution errors.
其关键则是程序对于