为什么计算机要区分好几种“空”

从 null、void 到 IT 背后的哲学

一位思考者坐在现实世界与数字系统之间,右侧展示 null、void、空字符串和空数组四种不同的空
从现实世界到计算机世界
现实进入计算机之前,必须先被拆分、命名和重新定义。null、void、空字符串与空数组,代表的并不是同一种“空”。

有一天,我突然想到一个好玩的事:

如果一个 IT 人喜欢思考,他其实很容易成为一个哲学家。

我不是说程序员天生就爱谈逻辑,也不是因为代码看起来深奥,而是因为 IT 所做的事情,本身就带有一种哲学性质:

它必须重新定义世界最基本的概念。

什么叫存在?
什么叫空?
什么叫同一个人?
什么叫状态发生了改变?
什么叫一件事情已经发生,却没有产生返回结果?

这些问题若不先被回答,现实世界就无法进入计算机。

准确地说,IT 并不是简单地把现实搬进机器。现实太混乱、太连续,也太暧昧,无法被机器直接理解。IT 必须先把现实拆开、命名、分类、建立关系,再把它重建为一个可以运行的世界。

只有经过这场抽象,世界才能在 IT 中站立。

一、现实世界可以含糊,计算机世界不可以

人在日常生活中可以说:“这个地方是空的。”
但计算机马上会追问:究竟是哪一种空?

是这个位置本来就不应该有东西,还是应该有东西,却暂时没有?
是尚未赋值,还是已经清除?
是没有返回结果,还是返回了一个代表“空”的结果?

人可以把这些情况混在一起,机器却不能。

于是,编程语言不得不发明不同的“空”:

void,通常表示一个过程不返回值。
null,表示这里有一个位置,但现在没有对象。
undefined,常常表示某个值尚未被定义,或者根本没有出现。
空字符串 "" 则不是没有值,而是一个确实存在的字符串,只不过长度为零。
空数组也不是“什么都没有”。数组存在,只是其中暂时没有成员。

在人看来,它们似乎都是“空”;在计算机看来,却是几种完全不同的存在状态。

这已经不是普通的工程分类,而是一套微型存在论。

二、void 与 null:两种不同的“无”

voidnull 看起来都像“没有”,但它们表达的并不是同一种没有。

一个函数返回 void,通常不是说它没有发生任何事情。相反,它可能已经写入文件、更新数据库、发送消息,或者改变了系统状态。它只是没有向调用者返回一个值。

因此,void 更接近:

事情已经发生,但没有可以带走的结果。

它不是存在的缺席,而是返回值的缺席。

null 则不同。
null 通常意味着:这里原本允许指向某个对象,但现在没有指向任何对象。位置还在,结构还在,期待也还在,只是对象缺席了。

因此,null 更接近:

这里本应可以有某物,但此刻没有。

这也是为什么空指针错误如此危险。程序沿着一个引用去寻找对象,最后却发现,那个位置后面什么也没有。

系统不是因为“无”而崩溃,而是因为它把一种“无”误认为了“有”。

很多现实悲剧也是如此。真正危险的往往不是不知道,而是把缺席误认为存在,把愿望误认为事实,把名称误认为实体。

null、void、空字符串和空数组四种编程中的空值概念对比图
计算机里的“空”,并不都一样
null 是对象的缺席,void 是返回值的缺席,空字符串和空数组则是确实存在、但内容为空的数据结构。人类语言可以含糊,计算机却必须区分。

三、对象:世界必须先成为“某物”

面向对象程序设计中最常见的词是“对象”。

什么是对象?
一个对象必须具有身份、属性和行为。

一个用户有姓名、邮箱、权限和登录状态;
一个订单有编号、金额、商品和支付状态;
一家公司有员工、客户、资产和业务规则。

现实中的人和事原本是流动的、复杂的,甚至充满矛盾。但进入系统之后,它们必须被定义为某种可以识别、保存和处理的东西。

这意味着,建立信息系统的第一步并不是写代码,而是回答:

这个世界究竟由什么东西组成?

这是一个非常古老的哲学问题。

柏拉图寻找理念,亚里士多德讨论实体与属性,
现代程序员则设计类、字段、接口和数据模型。

哲学家用概念描述世界,程序员用模型重建世界。

区别在于:哲学模型可以停留在思想中,程序模型必须运行。

四、身份:什么时候还是“同一个人”

现实世界中的“同一个人”,似乎不需要解释。
可是进入 IT 系统之后,身份立刻成为问题。

姓名相同,是同一个人吗?
邮箱改变了,还是原来的用户吗?
身份证号码录错一位,是新人,还是旧人的错误记录?
两个系统中的两条数据,究竟代表两个人,还是同一个人在不同数据库中的投影?

于是,IT 必须区分姓名、标识符、账号、凭证与真实身份。

用户名不是人,邮箱不是人,数据库中的一行记录也不是人。它们只是系统为了识别人而建立的代理。

但系统运行久了,人们很容易反过来相信:记录就是本人,评分就是能力,标签就是人格,画像就是一个人的全部。

这也是 IT 最深的哲学风险之一:

为了让世界进入系统,我们必须简化世界;但简化成功以后,我们又很容易把模型误认为世界本身。

地图原本只是为了寻找道路,最后却可能反过来决定什么地方值得存在。

五、状态:存在不是静止,而是变化

在信息系统里,一个对象仅仅“存在”还不够,它还必须处于某种状态。

订单是待支付、已支付、已发货,还是已取消?
用户是游客、会员、管理员,还是已冻结?
文档是草稿、审核中、已发布,还是已归档?
同一个对象,因为状态不同,可以拥有完全不同的意义。

这说明 IT 对存在的理解并不是静态的。一个东西是什么,不仅取决于它有哪些属性,也取决于它正处于什么阶段,以及它能够转变成什么。

然而,状态不能随意变化。

已取消的订单不能突然变成已发货;
已删除的账户不能在没有恢复程序的情况下继续登录;
未经审核的内容不能直接成为正式发布版本。

因此,系统必须定义合法的状态转换。

现实生活常常允许人含糊地说:“事情差不多办完了。”
计算机却必须知道:到底完成了没有?

在数据库里,含糊不是温柔,而是错误。

六、权限:存在并不等于有权使用

IT 还重新定义了一个政治哲学问题:权力。

一个对象存在于系统中,不等于所有人都可以看到它;
一个人能够看到,不等于能够修改;
能够修改,不等于能够删除;
能够操作,不等于有权授权别人操作。

于是,系统必须区分所有权、访问权、操作权和管理权。

这与现实政治中的权利、权力、权威十分相似。

很多系统事故,本质上并不是技术故障,而是权力边界设计失败:谁可以做什么,没有被定义清楚;或者本来只应拥有局部权限的人,得到了整个系统的钥匙。

从这个角度看,权限系统就是一种微型宪政。
它不假定每个人永远善良,而是预先承认:权力必须被限制,行为必须被记录,关键操作必须可以追溯。

好的系统从不依靠“大家自觉”。
它把不信任写进结构,同时又为合作保留可能。

现实街景逐渐转化为对象、身份、状态和权限等数字系统结构
现实必须先被重新定义
一个现实中的人或事物进入信息系统后,会被重新表达为对象、身份、状态和权限。系统能够运行,并不意味着它已经完整理解了现实。

七、IT 人何以接近哲学

当然,并不是每一个写代码的人都是哲学家,正如并不是每一个会说话的人都是思想家。

但一个真正喜欢追问的 IT 人,会很自然地走向哲学。

因为他迟早会发现,技术问题的底层往往不是技术。

数据模型设计失败,可能是因为没有想清楚事物的边界。
权限体系混乱,可能是因为没有区分权利与权力。
人工智能产生偏差,可能是因为人把带有价值判断的数据,当成了中性的事实。
系统不断增加补丁,可能是因为最初对世界的理解就是错误的。

代码只是把这种错误忠实地执行了出来。

机器不会替人解决哲学问题。机器只是迫使人把那些原本可以含糊过去的问题,明确写出来。

什么是一个人?
什么算一次完成?
什么叫相同?
什么叫拥有?
什么叫不存在?
什么可以改变,什么不可越界?

这些都是哲学问题,也是 IT 系统每天都在回答的问题。

八、代码不是世界,却暴露了我们如何理解世界

IT 最深刻的地方,不在于它制造了多少工具,而在于它迫使人类把自己理解世界的方式形式化。

在现实中,我们可以依靠经验、默契和常识生活;在系统中,一切都必须被定义。

定义不清,系统便无法运行。
定义错误,系统也许仍然能够运行,却会稳定、快速而大规模地制造错误。

因此,真正重要的从来不只是代码写得对不对,而是代码背后的世界观是否成立。

程序员写下一个对象、一条规则、一种权限、一个空值判断时,看似只是在处理技术细节,实际上却在决定:

什么可以存在,什么必须缺席;
什么能够发生,什么应当被禁止;
什么被系统看见,什么将被系统遗忘。

哲学家用语言解释世界。
IT 人则必须把一种对世界的解释,变成可以运行的结构。

也正因为如此,当一个 IT 人开始认真思考,他很难不接近哲学。

因为他逐渐明白:

世界之所以能够在 IT 中站立,不是因为机器足够强大,而是因为人先为世界建立了一套关于存在、关系、时间、身份与秩序的定义。

而所有定义的背后,都藏着一个尚未被写进代码的问题:

我们所建立的,究竟只是一个能够运行的系统,还是一个值得人生活其中的世界?

X

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注