设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

伴随我成长的编程书

2013-5-28 11:20| 发布者: 红黑魂| 查看: 2231| 评论: 0|来自: 博客园

摘要: 一、 这篇文章是应之前在微博上爆过的下个周末某出版社的线下活动而写的。回顾我和C++在这个世纪的第二个春天开始发生过的种种事情,我发现我并不是用一个正常的方法来学会如何正常使用C++的。我的C++学习伴随着很多 ...

令人遗憾的是,在我得到这本书的同时,Borland也把Delphi独立出来做了一个叫做Codegear的公司,后来转手卖掉了。我在用Delphi的时候还想着,以后干脆去Borland算了,东西做得那么好,在那里工作肯定很开心。我在高中的时候还曾经把Borland那个漂亮的总部的图片给我妈看过,不过她一直以为是微软的。于是我在伤心了两个晚上之后,看了一眼为了做参考我带到学校来的《Visual C++ 5.0语言参考手册》,找了一个盗版的Visual C++ 2005,开始决定把时间投入在C++上面了。于是Delphi之旅到此结束,从此之后,就是C++的时光了。

四、

学习图形学的内容让我学会了如何写一个高性能的计算密集型程序,也让我不会跟很多程序员一样排斥数学的内容。学习Delphi让我开阔了眼界的同时,还有机会让我了解Delphi内部工作原理和细节。这一切都为我之后做那些靠谱的编译器打下了基础。

因为在高三的时候我在不懂得《编译原理》和大部分数据结构的知识的情况下,用Delphi写出了一个Pascal脚本引擎,所以当我听说我大学的班主任是教编译原理的时候,我就很开心,去跟她交流这方面的内容,把我当时的设想也拿给她看。当然我的设想,没有理论基础的知识,都是很糟糕的,于是班主任就给了我一本《编译原理》。当然,这并不是《龙书》,而是一本质量普通的书。不过当我了解了这方面的内容之后,《龙书》的大名也就进入我的耳朵里了:
image
由于之前用很愚蠢的方法写了个Pascal脚本的缘故,看《龙书》之后很容易就理解了里面各种精妙的算法在工程上的好处。我之前的作法是先用扫描的方法切下一个一个的token,然后做一个递归来递归去复杂到自己都没法看的一遍扫描生成简单指令的方法来做。程序写出来之后我当场就已经看不懂了。自从看了《龙书》之后,我才知道这些过程可以用token和语法树来对算法之间进行解耦。不过《龙书》的性质也是跟《Visual Basic 高级图形程序设计教程》一样,是入门类的书籍。用来理解一下编译器的运作过程是没问题的,但是一旦需要用到高级的知识。

这个时候我已经初步理解了编译器前端的一些知识,但是后端——譬如代码生成和垃圾收集——却还是一知半解。不过这并不妨碍我用好的前端知识和烂的后端知识来做出一个东西来。当时我简单看了一下Java语言的语法,把我不喜欢的那些东西砍掉,然后给他加上了泛型。Java那个时候的泛型实现好像也是刚刚出现的,但是我不知道,我也从来没想过泛型要怎么实现。所以当时我想来想去做了一个决定,泛型只让编译器去检查就好了,编译的时候那些T都当成object来处理,然后就把东西做出来了。我本来以为我这种偷工减料拆东墙补西墙忽悠傻逼用户的方法是业界所不容的,不过后来发现Java竟然也是那么做的,让我觉得我一定要黑他一辈子。后来我用我做的这个破语言写了一个俄罗斯方块的游戏,拿给了我的班主任看,向她证明她拿给我的书我没有白看。

不过由于受到了Delphi的影响,我并没有在我的C++代码里面使用泛型。当时由于不了解STL,也懒得去看,于是自己就尝试折腾这么几个容器类自己用。现在代码还留着,可以给大家贴一段:
image
这段代码已经可以作为反面教材使用了。除了基类有一个virtual的析构函数和代码对齐的比较漂亮以外,基本所有的地方都是设计错误的典型表现。为了这段代码的贴图我特地在硬盘里面翻出来了我那个山寨Java脚本的代码,一打开就有一股傻逼的气息扑面而来,截图放进word之后,屏幕犹如溢屎,内容不堪入目。

之所以把代码写成这样,跟Delphi的class不是值类型的这个功能是分不开的。写了几年的Delphi之后,再加上第一次开始写有点小规模的C++程序,我从来没考虑过一个用来new的class是可以创建成值类型的。所以那个时候我一直处于用C++的语法来写Delphi的状态上。当然这样是不对的,但是因为那一段时间运气比较背,好的C++书都没给我碰上,直到我看到了《C++语言的设计和演化》
image
C++他爹写的这本《C++语言的设计和演化》是一本好书,我认为每一个学习C++的人都应该看。本来《C++Primer》也是一本不错的书,不过因为我阴差阳错用了《Visual C++ 5.0 语言参考手册》入门,所以这本书就被我跳过了。一开始C++用得很烂,觉得浑身不舒服,但是有知道为什么。看了这本书之后很多疑问就解决了。

《C++语言的设计和演化》讲的是当年C++他爹发明C++的时候如何对语言的各种功能做取舍的故事。在这个长篇小说里面,C++他爹不厌其烦地说,虽然C++看起来很鸟,但是如果不这样做,那就会更鸟。看完了这本书之后,基本上就剩下不会模板元编程了,剩下的语言的功能都知道在什么时候应该用,什么时候不该用。C++他爹还描述了一些重要的类——譬如说智能指针和STL的迭代器——在语义上的意思。其实这就跟我们在看待C++11的shared_ptr、unique_ptr和weak_ptr的时候,不要去想这是一个delete对象的策略,而是要想这是一个描述对象所有权关系的这么个“关键字”一样。有些时候细节看得太明白,而忽略了更高层次上的抽象,此乃见树木不见森林。

C++知道每一个特性如何正常使用还不够,如果不知道他们是如何实现的,那有可能在非常极端的情况下,写出来的程序会发挥的不好。正如同如果你知道C++编译器、操作系统和CPU内部是如何处理这些东西的细节,如果你顺着他们去写你的程序的话,那性能的提高会特别明显。譬如说在做渲染器的时候,为什么光线追踪要按照希尔伯特顺序来发射光线,为什么KD树可以把每一个节点压缩成8个字节的同时还会建议你按层来排列他们,都是因为这些背后的细节所致。这些细节做得好,渲染器的效率提高一倍是完全没问题的。这些知识固然很多,但是C++的那部分,却包含在了一本《深度探索C++对象模型》里面:
image
读《深度探索C++对象模型》,不仅仅是为了知道C++在涉及虚拟多重继承基类的成员函数指针结构是怎样的,而且你还可以从中学到很多技巧——当然是指数据结构的技巧。这本书的内容大概分为两个部分。第一个部分就跟需求一样,会跟你介绍C++的对象模型的语义,主要就是告诉你,如果你这样写,那你就可以获得XXX,失去YYY。第二部分就跟实现一样。按照需求来得到一个好的实现总是一个程序员想做的事情,那么这就是个很好的例子。正常使用C++需要的无限智慧,大部分就包含在上面这两本书里面。一旦把这两本书的内容都理解好,以后写起C++的代码都会得心应手,不会被各种坑所困扰,正确审视自己的代码。

文章之前的部分有提到过,让我正视理论和方法论的意义的是《凌波微步》,所以当工具都掌握的差不多的时候,总需要花时间补一补这方面的内容。首当其冲当然就是大家喜闻乐见的《算法导论》了。我记得当时是唐良同学推荐给我的这本书,还重点强调了一定要看原文,因为中文的翻译不行。所以我就在一个春光明媚的早上,来到了广州天河书城,把这本书搞到手。
image
这本书的封面颜色暗示着你,想读这本书, 应该去一个山清水秀绿荫环绕的地方。事实证明这是对的。在差不多考英语四级的前后,我有一段时间每天都去华南理工大学那个著名的分手亭看这本书。亭子后面是一个湖,前面有很多树和杂草,旁边还有一个艺术学院,充满了人文的气息。在这种地方看《算法导论》,不仅吸收得快,而且过了一年,我真的分手了。

说实话这本书我没有看完,而且那些证明的部分我都跳过了,实在是对这些东西没有兴趣。不过关于数据结构和大部分算法我看得很仔细。于是我在这方面的能力就大幅度提高——当然跟那些搞ACM的人相比反应还是不够快,不过我的志向并不在这里。除此之外,我通过《算法导论》也学到了如何准确的计算一个函数的时间复杂度和空间复杂度。事实证明这个技能十分重要,不仅可以用来找bug,还可以用来面试。

五、

对于一个读计算机的大学生来说,算法懂了,工具会了,接下来就是开眼界了。不过这些东西我觉得是没法强求的,就像下面这本《程序设计语言——实践之路》一样,都是靠运气才到手的——这是一个小师妹送我的生日礼物:
image
原本学习的汇编也好,VB、Delphi和C++也好,都是同一类的编程语言。这导致我在相当长的时间里面都无疑为编程就差不多是这个样子。直到我看到了《程序设计语言——实践之路》。这本书告诉我,这个世界上除了命令是语言,还有各种不同的编程的范式和方法。于是借着这本书的机会,我了解到世界上还有Prolog、Erlang和Haskell这么美妙的语言。

这对我的触动很大。一直以来我都是用一种编程方法来解决所有我遇到的问题的。然后突然有一天,我发现有很多问题用别的方法来解决更好,于是我就开始去研究这方面的内容。一开始我的认识还是比较浅,应用这些方法的时候还处于只能了解表面的状态,譬如说曾经流行过几天的Fluent Interface,还有声明式编程啊,AOP等等。直到我遇到了这本全面改变我对C++模板看法的书——《Real World Haskell》:
image
是的,你没看错,是《Real World Haskell》!Haskell颠覆了我的世界观,让我第一次知道,原来代码也是可以推导的。说实话我用Haskell用的并不熟,而且我也没写过多少个Haskell的大程序,但是Haskell的很多方面我都去花了很长时间去了解,譬如那个著名的Monad。多亏了当时搞明白了Monad,我借助这方面的知识,理解了《Monadic Parser Combinator》这篇论文,还看懂ajoo那篇著名的面向组合子编程系列

当我终于明白了Haskell的类型推导之后,我终于体会到了Haskell和C++之间的巨大差异——Haskell的程序的逻辑,都是完全表达在函数签名上的类型里面,而不是代码里的。当你写一个Haskell函数的时候,你首先要知道你的函数是什么类型的,接下来你就把代码当成是方程的解一样,找到一个满足类型要求的实现。Haskell的表达式一环扣一环,几乎每两个部分的类型都互相制约,要求特别严格。导致Haskell的程序只要编译通过,基本上不用运行都有95%的概率是靠谱的,这一点其他语言远远达不到。而且Haskell的类库(Hackage)之多覆盖GUI、GPU程序、分布式、并发支持、图像处理,甚至是网页(Haskell Server Page)都有,用来写实用的程序完全没问题。之所以Haskell不流行,我觉得仅有的原因就是对初学者来说太难了,但是人们一旦熟悉了C的那一套,看Haskell的难度就更大了,比什么都不会的时候更大。

于是回过头来,模板元编程也就变成一个很自然的东西了。你把模板元编程看成是一门语言,把“类型”本身看成是一个巨大的带参数enum的一部分(scala叫case type),于是类型的名字就变成了值,那么模板元编程的技巧,其实就是对类型进行变换、操作和计算的过程。接下来只要会用模板的形式来表达if、while、函数调用和类型匹配,那掌握模板元编程是顺利成章的事情。撇去type traits这些只是模板元编程的具体应用不说,只要熟悉了Haskell,熟悉C++的模板语法,学会模板元编程,只需要一个下午——就是学会用蹩脚的方法来写那些你早就熟悉了的控制流语句罢了。

当模板元编程变成了跟写i++一样自然的东西之后,我看语言的感觉也变了。现在看到一个程序语言,再也不是学习与发这么简单了,而是可以看到作者设计这门语言的时候想灌输给你的价值观。譬如说,为什么C语言的typedef长那个样子的?因为他想告诉你,你int a;定义的是一个变量,那么typedef int a;就把这个变量的名字改成了类型的名字。为什么C语言定义函数的时候,参数是用逗号隔开?因为你调用函数的时候,也是用逗号来隔开参数的。这就是语法里面的一致性问题。一个一致性好的语言,一个有编程经验初学者只要学习到了其中的一部分,就可以推测他所想要的未知特性究竟是如何用于发表达出来的。一个一致性差的语言,你每一次学到一个新的功能或者语法,都是一个全新的形式,到处杂乱无章,让人无可适从(所以我很讨厌go,还不把go的library移植成C++直接用C++写算了)。

从此之后,我就从一个解决问题的程序员,变成一个研究编程本身的程序员了。当然我并不去搞什么学术研究,我也不打算走在理论的前沿——这并不适合我,我还是觉得做一个程序员是更快乐一点的。这些知识在我后续学习开发编译器和设计语言的时候,起了决定性的作用。而且当你知道如何设计一个优美的语法,那么你用现有的语法来设计一个优美的library,也就不会那么难了。当然,设计优美的library是需要深入的了解正在使用的语言本身的,这样的话有可能维护这个library的门槛就会提高。不过这没有关系,这个世界上本来就有很多东西是2000块钱的程序员所无法完成的,譬如维护STL,维护linux内核,甚至是维护Microsoft Office。

六、

上面所列出来的书,每一本都是对我有深刻的影响的。当然光有深刻的影响是不够的,具体的领域的知识,还是需要更多的资料来深入研究,譬如说下面的一个单子,就是我在学习开发编译器和虚拟机的时候所看过的。内容都很深刻,很适合消磨时间。在这里我要感谢g9yuayon同学,他在我需要开阔眼界的时候,给我提供了大量的资料,让我得以快速成长,功不可没。

image
虚拟机——系统与进程的通用平台

image
Garbage Collection——Algorithms for Automatic Dynamic Memory Management

image
高级编译器设计与实现(鲸书)

image
程序设计语言理论基础

image
类型与程序设计语言

image
Parsing Techniques——A Practical Guide

image
The Implementation of Functional Programming Languages


酷毙

雷人

鲜花
1

鸡蛋

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部