欢迎任何困惑网上论战 strong type 和 weak type 语言是什么东西的萌新以及正在学习类型理论的人前来观看~
我只想说网络上大部分关于这部分的争吵都是错的! 而且出错的方向都太离谱了.
首先非常感谢客座作者 dannypsnl 大家可以看他博客!#
Type 本质上是什么东西#
Weak Type 与 Strong Type#
事实上你不能描述一个语言是不是 strong type 还是 weak type, 因为 strong 和 weak 每一个人都有一个内心的区间,当然对于大多数普通开发者而言这个区间范围都是错误的.
甚至对于专业的理论学者而言他们内心里的区间也是错误的,我们经过了一晚上的讨论终于大致把这个去加缩小到了下面五个范围,现在无论是学术界还是民科都无法用稳定的名词去描绘区间,我们只好尝试描述并举例.
第一梯队:运行时类型完整符合编译时类型且全部静态不可变更且理论完备#
这一梯队的语言基本不存在,因为这个区间能够保证整个语言运行在静态且可预测的状态,先不说停机问题,这种模型就限制了语言与外界的交互.
我们可以简单的科普一下历史,在遥远的 20 世纪,曾经有一个语言叫 Miranda (Haskell 的爹), 那个时候基本每个大学都有一个这个语言的 fork... 因为 Miranda 基本无法编写日常的程序,大家只好在上面糊一层又一层的 DSL 打各种各样的洞才能跑各种实际上有 **"意义"** 的程序.
这里的有意义的程序指的不是拿来发 PL paper 的也不是各种 type safe calculator.
基本不存在 Miranda 根本写不了任何跟本机交互的程序... 这是历史前提.
然后他们这一群大学进行了一次茶话会,最终创造出来并没有那么严谨的 Haskell.
(上面的历史有省略一部分内容,但大体上是这样的)
为什么他们自降等级到第二梯队?因为第一梯队的实际价值并不够普世,写不出程序的编程语言有什么诞生的必要呢?
所以我们总结一下:对于第一梯队的语言用户可以完全相信代码但写不出来任何有意义的程式.
第二梯队:运行时类型完整符合编译时类型且全部静态不可变更且理论完备的基础上允许 Casting#
- Haskell
- Rust
- C
只要我们允许了一部分 Casting 和打洞,我们就可以实际上的和现有的带有非常复杂的副作用的世界进行沟通了!通常在这一梯队的语言因为他们相对上理论更加的完备,从而能让完美了解他背后的理论的程序员可以无脑写代码.
(注意加粗字体)
但是往往他们的理论 (对于正常的本科学历且没有 PL 相关的知识的程序员) 非常的复杂如 Haskell 的 $System\ F_\omega$
但是这不代表说对于专业的程序员来讲这个就是坏事儿,但是总有那么一些 case 会不得不绕大圈子,俗称做类型体操.
我们可以总结一下在这个梯队的语言是需要一定专业的知识就可以无脑写出安全的代码,对于这一梯队的语言往往评价非常的两极分化.
最近火起来的 Rust 语言大体上也在这个位置.
其实 C 语言也在这个位置,但是关于 C 我们一会儿再说.
第三梯队:有编译时类型且运行时动态不可变类型且有检查#
在这一梯队我们就可以看到非常最近流行的一些脚本语言了.
- elixir
- ruby3
- typed-racket
- typescript*(我们给他脸放到这个位置,否则我们还会再多一个叫有编译期不可靠类型同时与运行时行为无关的梯队)
这一梯队平时除了 ts 大家接触的可能都不是很多,其实就是本质上我们能够保证大部分 (上面的梯队是只要好好写代码基本所有) 代码都符合编译期间的类型检查,同时预留了诸如 any 这种东西来保证作为脚本语言的动态性.
这一个梯队的书写体验效果极佳,除非是专业人员过来,否则评价都清一色的一边倒的说好.
总结一下,这一梯队的主要的特点呢是用户不会遇到任何不符合作者期望的运行时错误,且用户可以在代码运行前相信大部分代码.
第四梯队:无编译时类型有运行时动态不可变类型且有检查#
这一部分语言就是我们平常人开始分不清是弱类型还是运行时强类型 (动态类型) 的语言了,比如说这个区间里包含几个代表语言.
-
JS* (这个没有在第五梯队,因为本质上来讲其实 JS 还是可以自圆其说的)
-
Erlang
-
Ruby2
这一个区间的语言呢用户不太会遇到不符合作者期望的运行时错误,用户在大部分情况下可以相信代码
(前提是你知道正确的行为是什么)
第五梯队:有运行时动态可变类型 (俗称弱类型)#
- Python
- Perl
- Php
这一类语言属于作者水平有限或者根本写的时候就没想过要流行或者当时技术限制导致的产物,特点主要是用户会遇到不符合期望的运行时错误, 用户只可以相信说明文档(前提是他有好好写) 完全不可以相信代码.
Type 的阶级会随着你看待这个语言的角度发生变化#
到这里有人其实会诧异为什么 C 语言会在第二梯队呢?
怎么引发了无数的 Bug 的 C 语言能跟 Haskell 站在一起?
其实,C 语言人家在造的时候就没有考虑到你可能会引发这种内存不安全的问题,所以这个问题本来就不在 C 要解决的问题的范畴之内,其次假如你当 C 语言是一个 nominal (就是名称类型) 类型的语言,他会落在第五梯队,但是假如你真的了解作者所期望的用途,你看待他的 type 是 size (也就是我们俗称的C ABI) 他就能够能达到第二梯队的严谨性,这就是为什么有的 C 程序员说 C 是一个非常严谨的语言但大部分人并不这么认为.
因为大部分人都对数字不敏感,这可能是我们的基因导致的 (
另外一个可能的路线: Structural Typing#
但是没有任何语言的成熟的实现,但是这一套东西确实能在第二阶描述出第四阶的行为.
语言的易用性和 Type 有什么关系?#
完全没有关系
没有统计学上的一致,你可以轻易的使用非常复杂且完备的 Type theory 做出烂的不行的语言.
之前谈的话确实有语法优势和类型简单的优势,但现在没有用 text editor 写代码了
过于灵活的语言无法写出良好的 IDE 插件,如 Racket 的 syntax macro 可以随便变更语法,如 reader macro 等
如 Ruby 到现在也没有良好的补全因为运行时生成大量的代码.
还有就是说语言的不可靠没有文档能不能写代码的问题,举个极端的例子,Haskell 程序员一般不需要任何注释,看 type 就懂了,打个比方 Hoogle
我们这群程序员不用记任何名称, 只用记住他类型长啥样子就行咯.
但是 Racket 程序员在写复杂工程的时候没有库作者的帮助解释他这是干啥的是不可能写好的.
还有一个至关重要的问题,工具链
才能决定这个语言容不容易用
打个比方说这里有个反人类语言叫 Rust, 它的语法丑陋,非常难写,可是人家有 Cargo 这种世界一流工具链,所以才能大杀四方,要是这个工具链是 Haskell 的 stack 估计这个语言早就凉了.
trait XXX<T: Send + Sync + Clone> {
type YYY<'a>: Future<Output = zzz::<AAA>::BBB<T>> where Self : 'a;
}
总结一下: Type 只能决定你能不能相信这个文件里躺着的代码的行为符不符合你的预期,Type soundness 的程度只能保证正确性而不能保证易用
为什么你会认为有的语言比另一种语言好?#
每个人所遇到的问题都不同,所要解决的东西都不同,对正确性的要求也不同,我这么 PL 的人不照样博客用 PHP 写,你更应该关注使用什么手段把事情做好而不是这个语言有没有 type.
很多时候你说他好不好都是出于你的经验,但问这个问题的人很大可能上并不是要做跟你相同的事情,你也不能够保证自己的路径是最优解,所以别乱推荐语言咯~
科研界 PL 人在干啥?#
- 造名词🤫
- 前往精神病院的路上🚑
- 正在准备怼我🤯
结语#
希望大家理性看待编程语言,他们真的就只是最平凡的一种工具.