1

我是 Eiffel 的新手,我试图了解“原始”类型(例如,INTEGER_32、REAL_64 等)是如何实现的。我对 EIFFEL 库类源文件中看似循环的依赖感到困惑。

原始类型被实现为非扩展父类的“扩展”版本。例如,INTEGER_32 是 INTEGER_REF_32 的扩展子代。(请注意,“扩展”并不意味着“实例”。扩展类是一个类,而不是一个对象。)

INTEGER_REF_32包含一个扩展 INTEGER_32 的实例。在 INTEGER_REF_32 对象中的某处必须有一个扩展整数是有道理的,但这意味着父级包含其子级的实例。

当您查看功能的定义时,它会变得更加混乱:

在 INTEGER_32 中,名为“as_integer_64”的特征/方法被简单地重新定义为“Result := Precurser”,其中 Precurser 意味着使用父级的特征。在父代 INTEGER_REF_32 中,“as_integer_64”被定义为“Result := item.as_integer_64”,其中“item”是展开后的 INTEGER_32!换句话说,孩子调用其父母的特征,父母调用孩子的特征。我也很困惑为什么扩展版本用看似等效的定义来明确重新定义“as_integer_64”。

我希望看到原始类型的实现细节终止,并表明某些特性是内部定义的。相反,我发现了这些循环定义。显然,编译器对原始类型的了解比源文本文件中出现的更多。当编译器看到它知道的原始类型时,编译器是否会忽略源文本,或者 Precurser 在这种情况下具有不同的含义?重新定义是对编译器的某种暗示,还是让解析器满意的东西?

4

2 回答 2

1

对基本类型的特征进行递归定义的原因之一是可重用性。详细的讨论可以在这篇论文中找到(不确定它是否在线可用):

亚历山大诉科格滕科夫。原始类型和可重用性的实现。– WOON'98 国际会议论文集,圣彼得堡,1998 年。

简而言之,如果一个基本类被用作某个其他类的祖先,那么这个类会继承所有的特性,如item+等。功能声明也取自基本类型。因为它们是使用基本类型的功能调用定义的,所以编译器知道如何生成代码。

于 2012-08-19T10:47:14.213 回答
0

实际上,如果你查看 INTEGER_32 的源代码,你会发现所有的例程都被实现为“内置”,这意味着 Eiffel 编译器正在为这些特性提供一个实现。

由于 EiffelBase(现称为 FreeELKS)设计中的历史原因,我们为每个基本类型设置了两个类:X 和 X_REF。如果我们必须重做核心库而不必担心向后兼容性,我们只会保留 X。不需要 X_REF 类。将 X_REF 类视为 CELL [X] 数据类型,即 X 的包装器。

现在,这些内置函数的 Eiffel Software 实现非常具体。使用 Precursor 看起来很奇怪,但这样做是为了允许旧代码模式工作,即使规范不再允许这些模式。同样,如果我们不得不放弃向后兼容性,我们将保持实现真正内置,而不显示编译器实际上会做什么。

本身,没有真正的递归定义。在 INTEGER_32_REF 中,“item”被视为 INTEGER_32 类型的属性,而在后代中,它被视为返回自身的查询。这就是为什么人们应该忽略 INTEGER_32_REF 类甚至存在的原因,它只是一个 CELL [INTGER_32_REF]。

于 2012-08-13T13:19:27.830 回答