@
lizon 你还是没找到点。
> 你认为一开始就应该给初学者提供比较完善的语言和类型系统,让初学者知道什么是对的,什么是先进的,以最快速度学习享受到现在最先进的理论成果,更多的关注语言本身的描述能力。
如果我认为“一开始就应该给初学者提供比较完善的语言和类型系统”,那么压根就不用提 C 了。
但是考虑实用,这种“比较完善”的东西并不存在,所以并不需要从这个角度考虑先从什么上手。
(不管实用的话,可以考虑 Racket ,但有些知识复用性比较差。)
> 我认为一开始应该提供给初学者最大的自由,暴露合适的硬件细节,让初学者明白计算机到底在做什么。
用 C 显然不是最大的自由,而且很容易让初学者搞不清计算机到底在做什么。
因为 C 暴露的硬件细节其实不多——至少没 C++多。而且经常暴露得很不地道。
例如考虑不相关指针比较是 UB 这点就可以明白实际上 C 自身的设计(强调可移植性)完全是和单一地址空间的简化实现假设相悖的,和 C++11/D 形成鲜明对比。
(其实理论上来讲这里 C 的设计更“正确”,只是实际上几乎并无卵用。)
注意,我猜你想要的“暴露硬件”就是这类语言设计蕴含的抽象假设。
如果是指操作硬件的接口,那么 C 无能为力。必须了解 C 以外的知识才能谈论是否能上手。这对初学者是不必要的负担。
> 我不明白学 C 的低效在哪,风险在哪。
低效有几方面的原因。
首先 C 涵盖的新手急需的知识点太少,学其它语言上手容易收获更多。
其次是教 C 的材料多数比较劣质,光是找到对路的参考资料就需要额外成本。
再次,即便教对了路, C 本身的一些古董劣质设计很容易造成先入为主的错误观念形成误导,阻碍进一步学习——除非有意忘掉一些东西——这就是低效。
核心风险是 C 没学好, C 以外的知识也没学好,另外还会教坏别的小朋友。
因为上面几个原因,拿 C 混搭基础课造成的麻烦比其它语言大得多。
> 面向初学者的教材几乎全是 C ,算法教材也大部分是 C 代码或者类 C 伪码,各大高校开设的计算机课程必定有 C ,已经为初学者尽可能降低了学习曲线。
这是错觉。问题包含几个方面:
不加前提地营造 C “够用”的假象,而不是在使用之前引导学生了解适用范围。
算法实现如果只是伪码描述目的还好,但似是而非的、和现实使用不怎么着边的实现风格就大有问题:这是在误导这类实现是“正常”的或者“不重要”的。
注意即便主题不是实现,作者仍然可以使它们接近实用的做法,而不是普遍地拿半成品搪塞。(当然并不是所有算法书都这么烂,但跟 C 沾边的主流如此。)
使用不容易自然过渡到实用场合的代码教学,使学习者最后至少要学会两套不太相干的写法才能体现出所学知识的用途,这显然不是“降低了学习曲线”,而是人为抬线。
> 初学者需要“学习 C ”,而不是“精通 C ”,不要去研究 C 语言本身的细枝末节,最主要是理解指针概念。
我说过了指针作为实现技巧是个小聪明,而作为语言特性是个烂发明。
如果你是指跟理解指针有助于和了解硬件,很遗憾,这个也是错觉。因为 C 的指针不是描述体系结构时使用的“指针”——有关联,但完全是两回事。
(不信,让这些自以为学会 C 的去看 ISA 手册,看看真正地道的“指针”和 C 的这玩意儿有多大出入,需要浪费多少额外时间才能明白自己想错了。)
另外,即便只是说 C ,我觉得不能理解为什么指针不靠谱的,不该视为理解了指针。具体地,真“搞清楚过指针运作原理”,除去程序语言理论专业知识,下面的一大半应该是能自己独自发现的:
https://github.com/FrankHB/pl-docs/blob/master/zh-CN/why-is-pointer-awful.md> 有底层知识的支持,很容易就能理解函数指针,回调,委托的关系;从来就没有所谓的引用传递,都是值复制;缓存一致性问题不单单出现在底层,数据库,分布式系统同样出现,在底层同样能接触“速度不够就要加缓存,有缓存就要解决缓存一致性问题”这个朴素道理;类型系统都是纸老虎,是数据就都得放到内存里算。
我很确信依赖实现支持的理解会造成一些典型的错误理解。实例很多。比如被 const folding 坑了的。
你后面一些理解也是典型 yy ,但对大多数用户影响更大的是原则性方法论错误:模糊问题和解的边界。谁来替你保证实际的实现和你想象的一样?出问题谁负责?
顺便,函数指针不管在 C 和 C++中都是大坑,因为甚至连对应的“地址”是什么都扯不清楚。这种 spec 基础问题表明这些语言不适合入门。
> 为什么 C 语言最合适,往上看,高级语言写法风格大都类 C ,要学习其他语言并无太大的不适应。
如果是“都”,那么稍微有点用。然而“大都”是最差的情况——似是而非,想要正确就基本不能合并学习路径复用历史知识,鸡肋。
> 类型系统一个语言一套,但是指针是每个计算机都有的;往下看,完全可以通过逆向 C 程序来往更底层的方向走。
你搞反了,“没有”类型系统是类型论应用的简化特例。这个特例对设计语言的人有点用——因为可以按需定制自己需要的类型系统而不是被渣语言设计恶心;但对多数用户纯属浪费——至少使在具体任务中以不够系统的方式重复造不知所谓的轮子代替缺少的静态契约检查变得有必要了。
C 之所以在 B 上加上了类型系统,主要初衷也就是为了避免这里的不利影响。只不过由于设计者和实现技术的局限性,很不地道罢了。
至于“一定有”指针那还是错觉,你对体系结构设计的见识太少。至少可以确定 ISA native 的 pointer 不保证说的是一回事且可以以一致的方式使用。如果地址操作数直接够用,完全不需要引入 CISC 风格的指针概念。
逆向 C 程序是为了逆向本身的需求,如果说了解底层,比直接学习 ISA 慢不知哪去了……
> 如果是做语言研究,连用 C 入个门都困难,或者跌入个 C 设计上的坑都要大呼小叫,我觉得可能他的能力不适合做语言研究。
如果做语言研究,连 C 那么多明显的窟窿(以至于不适合入门)在哪都找不到,我觉得无论如何都是白费劲。
C 作为样本研究是有价值的,所以可以一学。仅此而已。
现在业界做语言和实现原型主要是 Scheme 这样的 Lisp 系方言。为了让之前学的 C 不浪费而故意复用 C 的知识也基本就是浪费时间,经验不够的还不如死了这条心。
> 在不清楚这个初学者以后到底要干什么的情况下,在初学者连自己都不知道自己到底要干什么的情况下, C 是性价比最高的语言。
我不清楚你有没有看到我指出的不管出于什么实用目的,基本上都有比直接学 C 更高效的路径这点。所以把 C 排在技能列表前面性价比不可能是最高的。