In Ada, Primitive operations of a type T can only be defined in the package where T is defined. For example, if a Vehicules
package defines Car
and Bike
tagged record, both inheriting a common Vehicle
abstract tagged type, then all operations than can dispatch on the class-wide Vehicle'Class
type must be defined in this Vehicles
package.
Let's say that you do not want to add primitive operations: you do not have the permission to edit the source file, or you do not want to clutter the package with unrelated features.
Then, you cannot define operations in other packages that implicitely dispatches on type Vehicle'Class
.
For example, you may want to serialize vehicles (define a Vehicles_XML
package with a To_Xml
dispatching function) or display them as UI elements (define a Vehicles_GTK
package with Get_Label
, Get_Icon
, ... dispatching functions), etc.
The only way to perform dynamic dispatch is to write the code explicitely; for example, inside 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;
(And a Visitor pattern defined in Vehicles
and used elsewhere would work, of course, but that still requires the same kind of explicit dispatching code. edit in fact, no, but there is still some boilerplate code to write)
My question is then:
is there a reason why operations dynamically dispatching on T are restricted to be defined in the defining package of T?
Is this intentional? Is there some historical reasons behind this?
Thanks
EDIT:
Thanks for the current answers: basically, it seems that it is a matter of language implementation (freezing rules/virtual tables).
I agree that compilers are developped incrementally over time and that not all features fit nicely in an existing tool. As such, isolating dispatching operators in a unique package seems to be a decision mostly guided by existing implementations than by language design. Other languages outside of the C++/Java family provide dynamic dispatch without such requirement (e.g. OCaml, Lisp (CLOS); if that matters, those are also compiled languages, or more precisely, language for which compilers exist).
When I asked this question, I wanted to know if there were more fundamental reasons, at language specification level, behind this part of Ada specifications (otherwise, does it really mean that the specification assumes/enforces a particular implementation of dynamic disapatch?)
Ideally, I am looking for an authoritative source, like a rationale or guideline section in Reference Manuals, or any kind of archived discussion about this specific part of the language.
Vehicles
(ii) defines theVisit
procedures that dispatch on vehicle types and takes a visitorv
as a second argument; each procedure callsv.Visit_XXX
(whereXXX
varies for each known derived type) and (iii) implement derived visitor types in other packages (Vehicle_XML_Visitor
, ...). I think I don't enjoy writing visitor patterns again and again, though :-) - coredumpVisit_XXX
functions that depends on the actual type being visited. How would you use the record component? - coredump