在 Ada 中,类型 T 的原始操作只能在定义了 T 的包中定义。例如,如果一个Vehicules
包定义Car
并Bike
标记了记录,它们都继承了一个通用的Vehicle
抽象标记类型,那么所有可以在类范围Vehicle'Class
类型上调度的操作都必须在这个Vehicles
包中定义。
假设您不想添加原始操作:您没有编辑源文件的权限,或者您不想用不相关的功能使包混乱。
然后,您不能在其他包中定义隐式调度 type的操作Vehicle'Class
。例如,您可能想要序列化车辆(定义Vehicles_XML
带有To_Xml
调度功能的包)或将它们显示为 UI 元素(使用, , ... 调度功能定义Vehicles_GTK
包)等。执行动态调度的唯一方法是编写代码明确;例如,里面:Get_Label
Get_Icon
Vechicle_XML
if V in Car'Class then
return Car_XML (Car (V));
else
if V in Bike'Class then
return Bike_XML (Bike (V));
else
raise Constraint_Error
with "Vehicle_XML is only defined for Car and Bike."
end if;
(当然,在其他地方定义和使用的访问者模式Vehicles
也可以工作,但这仍然需要相同类型的显式调度代码。实际上编辑,不,但仍然需要编写一些样板代码)
我的问题是:
为什么在 T 上动态调度的操作仅限于在 T 的定义包中定义?
这是故意的吗?这背后有什么历史原因吗?
谢谢
编辑:
感谢当前的答案:基本上,这似乎是语言实现的问题(冻结规则/虚拟表)。
我同意编译器是随着时间的推移逐渐开发的,并且并非所有功能都很好地适合现有工具。因此,将调度运算符隔离在一个独特的包中似乎是一个主要受现有实现指导而不是语言设计的决定。C++/Java 家族之外的其他语言在没有这种要求的情况下提供动态调度(例如 OCaml、Lisp (CLOS);如果这很重要,它们也是编译语言,或者更准确地说,是存在编译器的语言)。
当我问这个问题时,我想知道在语言规范级别,这部分 Ada 规范背后是否有更根本的原因(否则,这是否真的意味着规范假设/强制执行动态调度的特定实现?)
理想情况下,我正在寻找权威来源,例如参考手册中的基本原理或指南部分,或有关该语言特定部分的任何类型的存档讨论。