关于信息隐藏的感想及其它废话
最近在把数据底层的索引块内查找技巧升级到一个新的版本,所以一直在用C写程序。毕竟是所谓的“低级/半低级”语言,几年来一直想看看C方面有什么书,遗憾(或幸运)的是和所有(除了四处猫腻的C++)语言一样,没找到任何哪怕值得瞎翻一下的书:有文档和互联网就足够了。
看很多人推荐《C语言接口与实现》,本来在买IT八卦书时想顺便买了,但是出于洁癖,下单前还是下载了电子版。作者很推崇类似typedef struct T *T这样的隐式指针类型,以隐藏接口之下的实现细节。其实这个做法也是我一开始就尝试的,毕竟写面向对象程序写惯了,很难摆脱类似的思维:从库作者的角度来看,被用户乱搞始终是心理的一个阴影。
但即使我自己也忍不住这么做,我也不得不再次指出这种所谓的信息隐藏只是一种口味,根本不是一种普适并朴素的实践。除了免不了脱了裤子放屁的嫌疑,它在一些环境中还很有可能添加麻烦。有的时候真的有点怀疑,任何企图越俎代庖、与邻为壑(这里的邻就是用户)的行为都是愚蠢的。
比如一个很具体的麻烦来自于C在这方面的设定。在使用默认的内存管理方式的情况下,如果企图配合“构造函数”返回隐式指针类型,造成的最明显的一个问题就是数据结构所需内存不能开在栈里:因为对于调用者来说,这个结构体根本是未定义的,不知道它的大小(还不提编译器抱怨这个表象)。
为什么有人希望把内存开在栈里?首先,此人肯定知道整个调用链上的内存使用不会造成栈溢出。其次,他想避开malloc带来的用屁股想都知道一定不可避免的overhead。(说白了还是因为C默认内存管理的设计粒度过大带来的【注】。令人惊奇的是,大多版本的C居然提供了在栈内开辟空间的函数alloca,但仔细察看它们就知道仅仅是鸡肋而已)。
考虑到这些,如书中那样(使用指针)设计接口在内存使用的灵活性上就成了问题。这是我们隐藏除大小外其它细节的行为和C的设定混合产生的副作用。在一个副作用出现的时候,很多人会认为这体现了“不能两全”的事物固有属性,我认为绝大多数时候这不过是文青的幼稚想法。
问题的根源往往还在于有人做的不够好:浅层次上往往是环境本身的不足;更多的是思想误区(Linus:精神/心智包袱)。比如有人会认为非要使用栈这是过度优化而完全不顾本来不存在这种限制的事实(这里“不存在”也有两个层次,一个层次是在具体环境中的实践;另一个层次是在当前环境之外更大环境中)。
就上面的例子(C语言中设计接口)而言,解决问题的“最佳实践”是什么?暴露所有信息、加入那些本来是隐式的信息。
我们当然可以在隐式指针类型的基础上将结构体的大小直接或间接(比如通过宏根据明确大小构造抽象类型的内存分配)的告知用户。但为了隐藏某些信息就去增加繁文缛节是毫无必要的(更别提那些限制用户使用的方法了)。如果有什么不想让别人动就写上“别动”难道还不足够?
我要说的另一个例子与编程无关,但也很说明问题。我有块7200.11的硬盘,幸运没碰见固件门,但却开始产生坏道。经过简单的查询,我知道只要把坏道全部找出放入p-list即可解决问题(因为坏道多了g-list会满)。问题是seagate可能出于不让用户调出隐藏空间的目的,并没有给出这个接口,最终它和我都要为此付出成本。
有很多显而易见直白做法处理这些问题,比如:所有坏道都可以放入一个更大的g-list并和保留空间交换,引起的性能下降告诉用户就行了;比如,放入p-list与向后扩展使用保留空间以保证硬盘容量不变不要绑在一起,用户可以容忍一定的空间损失;设计更直接的方法阻止用户取用非法地址,而不是通过隐藏;等等。更少的麻烦更低的成本。
写点读后感。
最近买了本书叫《复杂》,《GEB》的徒弟写的。首先说明的是与《GEB》相似,我当然可以通过阅读学习很多东西,但我仍然忍不住要说:又一个伪装成理科生的文科生;又是名头很大(“亚马逊十大科学图书”)、又是草根评价很高(“作者现在成长为该领域的权威”)。事实是这这本书瞄准的内容涵盖比《GEB》还广,可作者说话却更罗嗦更不精确。
科普读物看多了让我觉得某些“科学家”有一个共同之处,就是社会影响力比真正踏实做事的人要大得多。就写作而言,科普作家的水平也是越来越低了(霍金,至少早期的霍金是个例外)。当然书还是要读下去,谁叫她毕竟比我懂得多些呢,不过给人的感觉也就是仅此而已了。
本来还想写点关于“可变静态类型”的思考、结构抽象与过程抽象之间的匹配,一说远了没思路了。这两个问题前者思考了一段时间了;后者也是在具体工作中体会到的:当前的主流语言基本就是结构与过程的配合完成工作,这里存在的不一致性常常让事物不能按照最精确的方式工作(虽然大多数时候我们不在乎)。改天吧。
回到最初提到的那本书,显然该书作者没有真正认真的考虑这类问题;又粗略浏览了其它内容后,鉴于我不放心作者的认识水平,最终我就放弃了这本书。说实话这本书写的煞有其事,比如它会提到和面向对象的相似性、也会引用其它文献。但是我怀疑,这种努力达到的“专业性”充其量也仅仅是一种伪装而已,迷惑性大于实际意义(无论作者主观如何)。
如今这样的专家太多了,他们在互相之间传播未经消化的信息,然后再普及到大众。
比如可以看到,将实现隐藏在接口之后在面向对象中更多的是为了方便(也仅仅是方便、而不是必要条件)实现多态;而本书使用信息隐藏的大多数使用场合并不涉及这个问题。而以这种方式设计接口的调调贯穿了全书始终。最可怕的是,这些作者往往以一种专家平静的口吻叙述他所知道的,好像一切都是自然而然的事情。
这又涉及到我长期强调的自学和独立思考的能力。说到认真的出版物肯定不能没有,没有怎么入门呢?但除了参考类书目和少数如Knuth这样的权威的作品(可以发现的是,他们的书很少涉及方法论),我越来越觉得至少咱们这个行业,对于已经入门的选手,真的是信书有害了。
注:还是我过去提到过的,有的时候大家都以为自己在抽象,其实不过恰恰是在制造一个万金油式的怪物实现或做些除了添加麻烦毫无必要的无聊事情。通过观察可以知道,世界上大多数库和工具都有类似的问题。当然,可以自己做自己的工具和行为约定去解决一些具体问题;但我们做这些事的时候最好避开相同的误区。