介绍 Go/ Java /C/C++/ Swift 等编程语言是如何实现范型的

2022-03-27 10:15:53 +08:00
 bmpidev2019

写了篇介绍 Go/Java/C/C++/Swift 等编程语言是如何实现范型的。

文章地址:编程语言是如何实现范型的 · 构建我的被动收入

7614 次点击
所在节点    分享创造
31 条回复
GeruzoniAnsasu
2022-03-28 22:34:06 +08:00
@iceheart c++中字符类型和整型是同一种类型:

'1'+1 => (这里的类型应该是?)
Leviathann
2022-03-28 22:40:28 +08:00
@danc 现在很少提类型强弱而是提动静,因为强弱本来就没什么意义,影响的东西很小
bmpidev2019
2022-03-28 22:44:55 +08:00
@Leviathann 的确,这种分类价值不大,只是一个视角,c/c++放到弱类型主要是指针导致的,还有一些是有隐式类型转换导致类型不强
misaka19000
2022-03-31 09:48:49 +08:00
楼主换头像了?
anonymousar
2022-03-31 10:53:12 +08:00
强 /弱类型 区分主要是体现在 隐式类型转换 跟指针关系大吗?
c0xt30a
2022-04-01 20:58:42 +08:00
@bmpidev2019 C++ 里用户可以决定是否关掉隐式的类型转换的。这个跟类型的强弱有什么关系?

最简单的做法是


void f(int);
template< typename T > void f(T)=delete;

也可以用 SFINAE 来约束

template< typename T>
std::enable_if_t<std::is_same_v<T, int>> f( T );

往后一点 C++20 可以用 concept 来约束

void f(std::same_as<int> auto x);

未来的 C++23 很可能用 really 来约束

void f( really int x );
c0xt30a
2022-04-02 14:43:30 +08:00
4.1 过去了,特意说明下,上边回复最后那条是玩笑
FrankHB
2022-04-08 20:24:40 +08:00
1.先把词输入对。
范型(paradigm)
泛型(generics)
2.讨论泛型,C 放进来是用来嘲讽用的么。
这还是因为现在 C 有_Generic ,够当作底线了(但是 OP 一点没提)。
手工复制和旧式 C 宏连当作范型的底线都不配,因为和类型系统完全没有交互。
(原文评论区说无关是因为预处理器原因,这是错的,因为 pp phase 也是语言规范钦定的一部分,不应作为是否算是泛型实现的准则。否则 multi-stage programming 之类的就尬了。)
3.不要参考什么强类型弱类型之流只会让概念更加含混的伪劣资料来源。
所谓的强类型对立的就是“无”类型或者单一类型(unityped)。
更原则性上的错误在于这根本不属于类型检查,而是确保存在能被检查的类型的前提。
cf.github.com/FrankHB/pl-docs/blob/master/zh-CN/typing-vs-typechecking.md
4.装箱本质上和类型系统无关。
把装箱的外延缩小为几种 manifest typing 的语言的应用实例是一个常见理解偏差。
(cf.stackoverflow.com/a/69991369
利用装箱实现泛型只是用了箱和被装的对象的非同一性;技术上,这里拿来装出来的是不是箱并不重要。
对象布局根本上需要通过 ABI 约定,箱不是描述 ABI 的抽象。
5.类型擦除和装箱无关。(为什么是 ed 不是 ing ?)
没有箱的类型擦除一样可以实现某种意义上的泛型。
6.vtable 不一定是虚“函数”表(就 Java 来说,一般叫虚方法表)。
虚表这里只是用来替代 RTTI ,跟装箱也无关。
7.同上,图中的字典传递跟装箱也无关。
而且跟虚表并列的应该是字典(虽然这个词太滥了),同样是用来实现某种 RTTI 替代品。
文章和目录里倒是正常了一点。
原文评论区有说 Type Erasure/Dictionary ,这个也不确切,更准确地,应该是+。两者都算不上是完整的实现技术。
但是前者是任意 manifest typing 意义上必要的,后者只是针对静态语言静态区分数据和所谓泛型函数的可选优化。
8.文章里说的 type parameter 暗示实现的说法是错的。
type parameter 本来就是 parameteric polymorphism 的核心,没 type parameter 的系统根本不会叫做泛型。
原文的评论区也指出了这一点。
要有区别,就是 typing 意义上的强度,例如类型系统是否允许支持所谓的 non-type parameter (根本地,形式上还是 type ,比如 dependent type )。
9.文章链接的《透过 Rust 探索系统的本原:泛型》里把泛型函数从参数化类型中独立出来的做法在概念上是错的。
泛型函数的区别无非是类型参数和→这个类型构造器的交互,所以是参数化类型的一部分。
如果类型系统允许一个值同时居留于不带有→和带有→的类型(如类型擦除可以把*→*这个 kind 擦回*),那么单独考虑泛型函数差不多完全就是实现细节。
当然,考虑到带有→的 STLC (λ→)是 lambda cube 往其它类型系统(典型地,System F(λ2))扩展的原点,基本上会涉及泛型函数的语言都不允许这样做,即便类型擦除有能力实现;所以这点很容易被一般的作者忽视掉。
bmpidev2019
2022-04-08 22:59:30 +08:00
@FrankHB 感谢这么详细而专业的反馈!你说的有些我还没能理解,不过我会继续对文章做一定的修改。
lxdlam
2022-04-09 12:35:47 +08:00
@FrankHB 说得很好,感谢!昨天回复的比较着急,今天来看很多地方说的确实是不够准确的,关于 C 的部分我的本意其实是说纯文本替换并没有 type level 的工作,所以不算泛型,最后没写清楚。
chingli
2022-07-22 09:50:40 +08:00
我最近也正在学泛型,并准备写一篇读书笔记,正好就看到你这篇了。结合你的文章、文章末尾和这里的精彩评论,让我引以为戒了。

不过我觉得你要介绍泛型,还是不要东拉西扯太多不太相关的东西,另外要多参考一些权威的解释和论文,然后用自己的话复述出来,从目的、方法、效果等方面去写,要让人能快速入坑,逐渐深入。

比如这些参考文献:

* 维基百科的 “Generic programming”: https://en.wikipedia.org/wiki/Generic_programming

* What is Generic Programming?: https://web.archive.org/web/20051225114849/https://lcsd05.cs.tamu.edu/papers/dos_reis_et_al.pdf

* Generic programming: https://codedocs.org/what-is/generic-programming

* What is Generic Programming? : http://www.elegantcoding.com/2012/04/what-is-generic-programming.html

期待楼主再写一篇!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/843140

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX