Other Readings异读 返回作品
字号
主题
下载
下载全书

全书 · v0.1 · 2026-10-10

第2章:代码中的对象

加布里埃尔·约兰 · 2021 年原著 · 全书中文初译AI 辅助初译,未经人工终校第 4 / 10 单元

平行之处

戴维·M. 贝里认为:“面向对象软件中的计算隐喻,与[OOO]关于作为对象的对象的思辨所表达的原则,有许多相似之处。”[1] 面向对象本体论与面向对象编程之间有着惊人的相似性,尽管前者只是借用了后者的名称。[2] 本章将探索这些相似性。

面向对象编程被发明时,计算机编程的主导方式是命令式或过程式的。命令式编程意味着传达直接改变程序状态的计算语句。以这种方式设计的程序,大致通过逐步、线性地处理一组函数来运行。当这些语句被组合成语义单元,也就是“过程”时,我们就可以谈论过程式编程。过程用于将计算机程序中的命令编组,使大型程序更易维护。语句的组合也使代码可以复用,因为同一组语句能够被反复调用。它也使代码更加灵活,因为可以把参数交给一个过程来处理。参数可以理解为传给函数的值(即 f(x) 中的 x)。函数遵循同样的逻辑,但运算结果取决于传入的参数。

然而,这些改进还不足以处理天气预报这样的复杂计算任务。这样的任务需要模拟。尽管艾伦·夏皮罗在一段带有鲍德里亚意味的评论中嘲讽地指出,“美国的商业化文化,在实质上已经不再是一个真实世界:它早已是一个模拟。面向对象编程则是模拟的模拟”,[3] 但模拟天气系统或金融市场的需要,还是要求采用更精细的策略来组织计算机程序。面向对象编程提供了一种间接替代的进路,而不是把一串语句编组为过程,再让这些语句直接操纵程序状态。计算语句与数据被捆绑进对象。这些对象对程序的其余部分封闭起来,只能通过规定好的接口间接访问。在这一新的编程范式下,计算机程序员成为对象设计者,被迫为自己想映射进计算机内存的世界构想一种面向对象本体论。

面向对象的发明,使面向对象计算机语言成为必要。已有的计算机语言不具备描述对象及其关系所需的语法。由此可见,“计算机语言”或“编程语言”都是容易误导的术语。这些语言是人类的发明成果。它们由人类设计、可以为人类所理解,计算机则能够处理它们,以完成特定任务。设计一种编程语言,就是试图为未来的开发者制造一套工具,让他们解决尚未预见的问题,有时甚至以此前无法想象的方式来解决。信息学中的面向对象本体论是实用的、开放的。它们是实在论的,因为它们构成了一套有用的指称系统,用来指称计算机(或编程语言)之外的事物。它们旨在实现可复用的程序代码,使代码只需写一次,因此问题不必解决两次,错误也不必在多个地方修复。所以,编程语言设计者的任务是元实用的:设计一种作为工具的语言,供其他人用来构建工具,最终完成特定任务。面向对象抛弃了语句列表,转而把对象当作“问题解决”的场所——借用西蒙东的说法。西蒙东的个体概念把对象描述为 “相容化的能动者”,解决不同“量级”之间的问题。[4] 以这一观念,西蒙东预示了面向对象编程中的对象;或者至少,OOP 中对象的实际实现,证明与西蒙东所描述的个体特征是一致的。

面向对象编程之所以得到如此广泛的采用,部分原因在于它贴近日常的对象经验。它还大量使用了另一种日常概念:层级。对象即使内部发生剧烈变化,从外部看来也可能仍保持可识别性与稳定性。“开闭原则”就是一个证明:一个组件——未必是对象——必须对未来的扩展开放,但对于已经对外暴露的接口则应封闭。这种封闭确保依赖于该组件的其他组件,能够继续信赖它此前展示的功能;必须防止行为发生意外变化。[5] 封闭可以理解为统一性,理解为对象使自身可被识别的某种稳定性。不过,面向对象编程是通过将对象编织进一个层级来取得其中一部分稳定性的,而面向对象本体论拒绝这一观念。[6]

在面向对象编程与面向对象本体论中,对象都是占主导地位的结构要素。在面向对象编程中,对象应以现实生活中的对象为模型,因为目标是为所要模拟的现实提供足够精确的表征。然而,在实践中,这项事业往往失败。代码中会为程序之外并不存在的东西创建对象。功能被强行塞进对象形式,即使结果笨拙、令人不满也不例外。许多使用面向对象编程的软件工程师所面对的一个共同问题,也处于面向对象本体论的根本处:我们对对象知道得太少,不足以据此为世界建模。OOO 拥抱这种不确定性,OOP 却天真地否认它。被迫使用 OOP 的软件工程师,必须提出一个很可能错误、不充分或适得其反的世界模型;而采用函数式编程范式的软件开发者,则可以专注于需要发生什么,而非事物是什么样的。因此,其他编程范式近来得到越来越多关注,像苹果的 Swift 这样的新编程语言,也以不拘泥于教条的方式混合不同范式,目标是始终为具体用例提供最不容易出错的解决方案。但这不应成为我们的顾虑,因为我们关注的是 OOP 与 OOO 共有的诸多特征:

  1. 对象是两套系统的基本构件。
  1. 对象可以极其简单,也可以极其复杂。
  1. 对象有不向外部完全暴露的内部生活。
  1. 对象间接地与其他对象互动,不能完全穷尽其他对象。
  1. 对象可以摧毁其他对象。
  1. 从对象外部看,对象间互动的结果可能可以预测,也可能无法预测。
  1. 对象可以包含对象。
  1. 对象可以随时间变化,同时又在可识别实体的意义上保持为同一个对象。
  1. 不可能有两个相同的对象。

本章将考察其中一些更有意思的平行之处。

对象作为不可预测的集合体

第一种被视为面向对象的编程语言,是二十世纪六十年代由奥斯陆挪威计算中心的 Ole-Johan Dahl 与 Kristen Nygaard 发明的 Simula 67。Simula 67 被设计成一种以模拟为目标、用于描述系统的形式语言(因此得名 Simula,由 simulation 与 language 两词组合而成)。Simula 已经包含了面向对象的大多数主要概念。最重要的是,Dahl 与 Nygaard 对对象的定义至今依然成立:面向对象编程中的对象,是属性(数据)与代码(行为、逻辑、函数、方法)的集合体。这些对象暴露出一组规定好的接口,既不揭示对象能力的全部,又控制着信息流入和流出对象。这两个特点被归纳在“封装”这一名称之下。[7]

编程中的对象,是“古老的一与多的问题”的另一种变体:[8] 它们既以称为“类”或“对象类型”的抽象定义而存在,也以称为“对象”或“实例”的实际实体而存在。因此,类是对抽象对象的属性与行为的柏拉图式描述,实例则是这类描述在计算机内存中的实际实现。[9] 任何一个类都可以有不止一个实例;同一类的多个实例彼此通信,不仅可能,而且很常见。

让我们看一个具体例子,说明过程式编程与面向对象编程的区别。在过程式编程中,一个典型函数是 y=f(x),其中 f 是对 x 执行的函数,函数的结果被存储(返回)到变量 y 中。而在面向对象中,会引入一个包含方法 f 的对象 x。程序会定义一个接口,使其他对象能够按照指定模式调用 f。因此,通过调用 f,也就是对象 x 所包含的成员函数——简写为 x.f()——这个同时包含数据与功能的对象,始终留在其自身之内。在我们的例子中,没有返回值,因此也就没有用来保存函数 f 结果的 y。这并非必要,因为对象自身保存着它所操作的全部数据。

面向对象编程受到过这样一种批评:从严格数学的视角看,对象方法(对象内部的函数)的行为是不可预测的。一个数学函数 y=f(x) 应当只处理 x,并把结果返回到 y。但一个对象方法还可以修改其对象内部的其他变量,从而导致不可预测的结果。函数应当返回自己的结果;对象方法却是修改其对象,而未必返回整个修改后对象的副本(或指向它的指针)。当通过对象的某个成员函数操作对象时,从外部并不知道,这一操作在内部会对对象产生什么影响。这意味着,在这样一次方法调用之后,对象的行为无法从对象外部预测。软件开发者一般力图防止不可预测性,面向对象哲学家却几乎不会为之惊讶。对象可以以不可预测的方式行动,而且它们的内部性对一切直接访问封闭,这是 OOO 的关键特征:

我认为,面向对象编程通常最大的问题,在于人们以非常命令式的方式进行面向对象编程:对象封装着可变状态,你调用方法,或向对象发送消息,使它们修改自身,而其他引用这些对象的人对此并不知情。结果,你就遇到了令你意外、无法分析的副作用。[10]

在面向对象中,数据与对数据执行的操作必须捆绑在一个对象里;与之竞争的函数式编程范式,则意味着操作与数据彼此分离。例如,在函数式编程语言 Haskell 中,函数只能返回值,不能改变程序的状态(而面向对象则可以改变)。

柏拉图式的类

对象可能有复杂的内部运作(既包括代码,也包括数据),但通常不会与其他对象分享所有这些信息。对象暴露出某些明确定义的接口,通信通过它们才成为可能。按照面向对象最初的应用方式,我们将使用一个模拟程序来讨论 OOP 的关键概念。设想一个模拟我们太阳系中引力效应的程序。如果按面向对象方式设计,这种程序几乎肯定会包含一种代表行星的对象类型——或者说柏拉图式的“类”。这一类会包含变量,用于描述行星的物理与化学属性,例如直径、大气、年龄、当前平均温度、相对于太阳系中太阳的位置等等。它还会包含用来操作类数据的方法。还需要实现一种改变平均温度的方法,例如用于处理太阳缓慢衰亡的情形。在太阳系模拟中,行星类会有多个实例——即多个对象;就我们的太阳系而言,人们会为地球、木星、土星等创建对象。

模拟程序将通过调用对象相应的方法,操作任何一颗行星的数据;例如,调用改变行星 表面平均温度的方法。保存平均温度的实际变量本身不会向对象外部暴露。这样,任何与对象的互动,都必须通过对象所提供的接口方法来中介。这一中间层构造了与对象的一切互动,并能够检查错误输入。中介性的数据设置方法提供它自身的逻辑,因而也提供它自身的限制,防止对象遭到这类“误用”;例如,它不会让人直接把行星温度改为低于绝对零度的数值,而如果提供直接访问,这样做就是可能的。

但所有行星都各不相同。为了在模拟中考虑这一点,我们需要相应地设置每一个实例的属性(数据)。为此,类提供了特殊的“构造函数”方法,使类的一个实例得以产生。构造函数接收最初构造对象所需的参数,然后据此创建一个实例。(要摧毁对象,也可以使用所谓的“析构函数”。)

如前所述,面向对象编程区分类(对象类型)与对象。[11] 这一平行关系之所以有趣,在于构成对象的,是固定结构与自由浮动的偶性之间的相互作用。这种相互作用,就是 OOO 所视为对象本质的东西。为了不把 OOO 与 OOP 之间的类比推得太远,我们应当指出,在 OOO 中,这种相互作用发生于对象内部,而在 OOP 中,它跨越对象之间的边界。不过,与 OOO 中的情况类似,对象可以在并未主动实现任何现实的情况下产生。然而,OOP 中的对象结构(我们会把它称为与 OOO 的实在对象极相对应的东西)规定了对象能够做什么。这应被理解为一种潜能,而不是对对象能力的穷尽描述。在 OOP 中,一个对象的实例(我们已将其看作对象的实在性质极)不能还原为对象本身(实在对象极)——因此,对象始终多于其僵硬的结构。如果对象与外界有任何接口——OOP 中的大多数对象都是如此——仍然没有办法知道与该对象的一切可能互动会产生什么结果。

层级与继承

假设我们的太阳系模拟中的所有行星都已得到充分定义。我们仍然需要一个代表太阳的对象。太阳不是行星,而是恒星;但二者仍共享某些属性,可能也共享某些方法:那是所有天体都包含的东西。自 Simula 67 中的第一个实现版本起,使用面向对象编程范式,就等同于把对象按层级组织成树状结构。每个对象至少有一个父对象(超类),也可以有子对象(子类)。对象继承其超类(在某些情况下,是多个超类)的所有属性与方法,再把它们连同自身的属性和方法传递给子类;子类随后可以添加额外的属性与方法。因此,代表行星和太阳的两个类,都应从一个代表任何天体的超类派生出来。这个天体类将处理它的所有子类共有的属性与方法。只有行星或恒星这类更具体天体所必需的方法和数据,才会在各自的子类中定义。在 OOP 中,起作用的是一种反向的辅助性原则:凡是能在最高、最抽象层次处理的事情,都在那里处理;只有更具体的任务,才在对象层级更低处处理。

OOP 谈论“父类”“子类”和“继承”,这些术语显示了 OOP 所根植的层级传统。层级中的任何对象都从其父对象“继承”所有特征。这样的层级以一个抽象对象为根(在微软的 MFC 模型中是 CObject);它只由抽象方法构成,完全不说明这一对象的任何具体特征。软件开发者很少直接使用这样的对象,而只是通过它的某个更具体的子类来使用。但并非所有对象都属于这样一个层级,例如 MFC 模型中的 CTime 对象。[12] CTime 用于表示一个绝对时间值。对此类数值的操作非常基本,许多方法都需要用到;但要在一个包罗万象的层级系统中,为时间对象找到一个逻辑上恰当的位置,却很困难。某个特定时间的表征应该从什么派生出来?这个问题难以回答,因为这一概念过于基本,无法被嵌入一个层级。因此,虽然 CTime 对象可以整合进定制的层级, 但它们自身并不是从任何超类派生的:在 MFC 模型中,时间的表征是独立的对象。

接口与实现

既然我们的面向对象程序设计中已经表征了一个小型天体层级,我们仍然面对实现实际模拟算法的任务。讨论这一算法本身,超出了本书的范围。我们更感兴趣的是,在面向对象设计中,这样一个算法应该放在哪里。这触及任何面向对象系统中的一个关键问题,也是本书将反复回到的问题:过程在何处、以何种方式发生?它们发生于对象内部、对象之间,还是两个地方都会发生?西蒙东强调把对象看作通过生成而存在,[13] 而 OOP 与 OOO 的概念,则都依据对象的相对稳定性来定义对象。

在面向对象本体论中,实在对象需要感性对象作为彼此之间的桥梁,从而形成一条对象链。感性对象彼此之间、实在对象彼此之间,都不能直接接触。感性对象充当实在对象之间的接口,或者实在对象充当感性对象之间的接口。在面向对象编程中,对象也不能直接接触:它们被分为接口部分和实现部分。接口部分充当一个提供给其他对象的方法与变量的目录——这个目录是不完整的。它从不把对象内部的一切暴露给外部。它甚至可以宣告某些方法,而这些方法在宣告时还没有得到完整定义。只有这些方法被调用时,软件才会实时决定,当前情形适合使用方法的哪一个版本。因此,一方面,OOP 的接口是一个感性对象,因为它充当与其他对象交互的接口,同时并不暴露其实在对象——也就是实现部分——实现现实的全部能力。方法可以根据外部无法通达的标准执行不同的代码,从而允许程序在运行时改变,而不损害对象的可识别性。另一方面,实现部分则以对象在程序中实现作用的能力之总体,代表实在对象。

对于太阳系模拟,面向对象编程中显而易见的实现方案,是设置一个超类,用来表示在天体层次模拟太阳系所需的全部组成部分。这样一个太阳系类的实例,随后必须为太阳系中的每个天体纳入成员类。但究竟哪一个对象负责描述太阳系对象的所有数据与方法之间的关系?人们可以在太阳系类中创建方法,包含模拟所需的算法,例如随着时间推移,根据其他天体的位置与运动来修改一颗行星的空间位置。但处理这种模拟时,预期采用的方式是一种称为“消息传递”的技术。

对象可以发送和接收消息。消息传递的概念,允许把消息发送给一个对象,再由该对象决定如何处理消息。这样,对象就能够根据发送给它的数据类型,动态地处理请求。这说明了对象与对象互动的双方是如何参与的。这种互动并非简单的发送者—接收者关系,而是一种丰富的交换:参与其中的两个对象既不会完全接触彼此,又会选择究竟接受哪些输入。一个代表行星的对象,可以向其他行星对象发送消息,告知它们自己的空间位置。这些其他行星随后会相应改变自己的空间位置。借此,人们可以创建一个非常简单的引力模拟;但参与其中的对象,都无法访问其他对象那些在计算引力效应时不需要的属性。

因此,消息传递不仅是一个不可穷尽性的概念,也是一个间接性的概念。对象不会彼此穷尽,甚至不会直接接触,但它们的确通过消息交流,而消息可以看作感性对象概念的一种实现。

程序的不可穷尽性

最后再让我们回到太阳系模拟的例子。我们发现,面向对象编程语言提供的对象本体论是宽松的,因为可以有处于层级之外的对象。

太阳系对象,即承载我们模拟的对象,需要在某个时刻被实例化,因为它不能创建自己。太阳系类之外必须还有代码。当然,也许存在另一个代表星系的对象,它又纳入了太阳系类(成为太阳系的超类)。但银河系对于模拟我们太阳系中的引力效应并无用处,这样做只是把问题移到了另一个层次。面向对象编程范式,是对程序最终运行其上的硬件的一种抽象,因为中央处理器(CPU)并不“认识”对象。在 CPU 能够运行程序之前,编译器或解释器程序必须先完成把程序翻译成机器代码的任务——而在这一翻译之后,对 CPU 来说,对象概念就丢失了。这些翻译程序把面向对象还原为芯片能够处理的一系列十分基本的内存操作。只有建造出面向对象的硬件,使编译器或解释器变得无用,这一点才会改变——但像1981年推出的 Intel iAPX 432 这样的面向对象芯片设计,最终失败了。它们速度慢、价格贵,而更适应硬件局限的新技术被证明效率更高——所以,在芯片中采用面向对象这一想法,只找到了非常有限的应用。[14]

过去60年间,编程语言经历了漫长的发展历程。它们从用于直接访问处理器内存的一组原始命令,发展为复杂的语义,完全抽象于程序所运行的硬件。所有高级编程语言都需要一个中介,把用这种语言编写的语句与程序预计运行的硬件连接起来——这些中介要么是编译器(以耗时的方式把高级编程语言翻译成处理器能够处理的机器代码的程序),要么是解释器(基本上实时执行相同任务)。无论哪一种情况,在高级语言与机器之间,都有一个媒介。[15]

虽然我们曾将面向对象本体论中的对象描述为被分成实在与感性两个部分(并将其粗略比作编程中的实现与接口概念),但我们需要理解:高级编程语言中的语句,与所编写的程序将要运行其上的硬件之间,整个关系是 模型与现实的关系。芯片的硬件构成了程序的最终现实,因为硬件规定了叠加在它之上的模型必须面对并在其中工作的现实。而硬件的现实,又是它的语境:机器更广阔的环境、它的应用,以及使用它的人。

程序实现其现实的能力,受限于它运行其上的硬件与可用时间。只要时间充分,一个能够自我修改的程序就可以实现无限量的现实。因此,实在对象不能被它与感性对象所进入的关系穷尽。在芯片上运行的程序永远无法穷尽芯片。不可能列出所有能够在该芯片上执行的程序。人们甚至不可能事先知道,这些程序是否真的全都会终止。艾伦·图灵描述了这一现象,它后来被称为“停机问题”:任意一个计算机程序最终会结束运行,还是会永远运行下去,是不可判定的。[16] 停机问题把不可穷尽性(我们无法知道一个对象的总体)扩展到了不可穷尽性的证明(人们能否知道一个对象的总体,这一点本身就是不可理解的)。

面向对象本体论旨在平等对待所有对象,这排除了任何中央施事者。在面向对象编程中,似乎也没有中央施事者,对象的行动独立于任何中央实例。现实中,今天的面向对象,是一种叠加在硬件之上的范式;而硬件没有中央施事者就无法工作。因此,虽然用于为程序建模的语言是面向对象的,但必须理解,这些对象是在一种语言中的构造物,而这种语言又试图模仿现实中的事物与关系。

只要停留在对象的抽象层次上,对象就代表自身行动。在芯片层次,这些对象并不存在——CPU 只对存储了某些信息的内存进行操作。CPU 与操作系统会在对象不“知道”的情况下作出决策,例如进行调度:因为今天的程序大多在拥有不止一个中央处理器的计算机上运行,所以有必要把任务(或对象方法)分配给不同的 CPU。

我们被彼此具有某种独立性的对象包围,这一直觉处于 OOP 与 OOO 两种模型的根本处。 但面向对象本体论拒绝认为,对象可以还原为其他对象:即便每个对象都能分解成其各个部分(这些部分代表新的对象),这些对象也不会穷尽它们所形成的更大对象。在 OOO 中,对象“之下”没有任何东西。然而,OOP 是一个有意叠加在更原始、也不合直觉的内存计算概念之上的模型。

这表明,面向对象编程是一个只在特定抽象层次上起作用的模型。面向对象编程与面向对象本体论的主要区别就在这里:前者是在一个领域中实用地运用的模型,后者则以完整的形而上学为目标。

递归与部分接触

OOO 不允许对象之间有层级——它的本体论是扁平的。这看似与面向对象编程中的对象层级矛盾。但 OOO 的扁平性究竟意味着什么?面向对象本体论认为,康德在人与物自身之间划出的裂隙,并非这一特定关系所独有。[17] 它认为,所有对象之间都有一道裂隙;没有任何对象能够直接而穷尽地“接触”其他任何对象。因此,不可能存在一种垂直关系,使有生命、有意识的存在者对其他一切形成支配关系。这是否意味着,不能有任何其他类型的对象层级,作为排序手段,或者更准确地说,作为识别对象及其系统性关联方式的手段?虽然对象层级是面向对象编程最显著的特征之一,但就对象如何彼此互动或穷尽而言,这种秩序并不使某些对象优先于其他对象。甚至还有处于层级之外的对象(例如上述 CTime 对象)。看来,非层级性继承的观念适合面向对象本体论:OOO 把对象定义为独立于其部分与更广阔的语境,但这一定义造成了可识别性的问题。一个如此极端独立的东西,甚至可能根本无法被识别为一个东西。它与周围宇宙之间,必须有某种关系、某种交织。完全的非关系不可思议,然而哈曼认为,“部分自主性仍有待解释”:[18] “问题在于,对象无法被‘部分地’接触,因为在某种意义上, 对象没有部分。”[19] 如果对象没有可容许“部分接触”的部分,而对象又独立于自身的内外,OOO 如何能够解释对象的本质特征与对象本身之间的关系?

也许面向对象编程的继承概念在这里能够派上用场:它的层级并不在本体论上抬高某些对象——它甚至允许有层级之外的对象;层级唯一的目的,就是把对象的自相似性组织成结构。这种结构化,源自面向对象编程语言的实用性质:它们旨在使复杂现实可用语言表达,从而让(人类)软件开发者能够掌握。自相似对象的层级,在许多情况下都被证明有用。但正如前述太阳系模拟的例子,要发现这些层级,仍有赖于程序员观察他们[20] 想要映射进计算机内存的现实。如果把这一技术强行用于不具自相似特征的结构,它就不会很有用。不过,从太阳系到蕨叶,从闪电到贝壳,从山脉到海岸线,都可以在对象(或复合对象)中观察到随机的(而非精确的)自相似性。而且,自相似性不一定抬高人类视角,因为它是在自然中可以观察到的事实。

直到1975年,伯努瓦·曼德勃罗才描述了“在所有尺度上都同样‘粗糙’”的对象。[21] 与经典几何学的光滑形状相反,分形具有粗糙边缘。在这些粗糙边缘中,分形的形状反复出现。理论上,这种形状的重复没有限度,而在自然界中,一般观察到三到五次重复。无论看得多近,分形都不会变得更简单。

分形可以用递归函数创建,也就是用调用自身的函数创建。二十世纪初,美国数学家斯蒂芬·科尔·克林发明了这一技术;如今它在信息学中十分常见。我们希望把递归理论作为讨论 OOO 中部分接触问题的起点:一个对象始终有更广阔的语境可以消融其中,也始终有更微小的部分可供继续分解,它如何仍保持为一个可识别的对象,而不使对象重新融化成一团类似无定者的东西?哈曼提出,对象的感性性质可以部分地用于识别对象——但当对象通过与其他对象的关系形成新对象时,这种识别就 成了问题;而且,由于没有直接通达实在对象极的途径,我们如何能知道,我们谈论的不是仅仅有着显现完全相同的感性极的不同对象?

什么构成了对象的独立性,什么又构成了它的稳定性?递归理论提出,对象相对的独立性与稳定性,源于它与更广阔语境及自身部分的交织。对象是递归的,因为它们由自身在无尽递归链中的相对位置所定义。递归函数的一个实例保持独立,“如同莱布尼茨的单子那样统一”,[22] 却又编织于其递归之中——是作为整体,而非作为部分。所有对象相对于宇宙中其他对象,都占据一个相对位置,并且编织于更大的对象之中。它们的交织赋予它们部分稳定性,使其可以被识别为特定对象。如果它们没有以这种方式交织在一起,它们要么处于非关系中,从而绝对不可识别;要么可以被完全穷尽,这一方面使其容易识别,另一方面却会导向一个完全决定论的、甚至停止不动的世界。递归虽然解决了这一问题,却要求对象具有某种自相似性,而这恐怕并不是对象包含其他对象的必要条件。

实在对象是其实现现实的能力之总体,这必然包括对象的递归:对象始终只是无尽序列中的一个实体,尽管它是一个可识别的实体。但实在对象并非编织在一条线上,而是编织在一张网或某种其他结构中;第4章将尝试更详细地界定这一结构。

注释