!topic LSN on Minor Issues Related to Controlled Types !key LSN-1068 on Minor Issues Related to Controlled Types !reference RM9X-7.6;4.0 !from Bob Duff $Date: 94/01/29 17:05:31 $ $Revision: 1.3 $ !discussion This LSN discusses three issues related to controlled types, which were discussed at the recent DR/XRG meeting in the UK. Our proposals are: - Finalization and Split should not be abstract. - The implementation permission in RM9X-7.6.1(20) should be deleted. - The name of Split should be either Split or Post_Copy. ---------------- Finalization and Split should not be abstract. Instead, they should have a default implementation that does nothing, just like Initialize. This change has been suggested by the Swiss delegation (among others). Our reasoning is that in writing a Finalize operation, one should be able to have a simple coding convention: always call one's parent's Finalize operation. This coding convention won't work if Finalize is abstract, since such calls would sometimes be illegal. This argument is even more compelling in a generic, now that we have generic formal abstract tagged types (and we expect them to be more common than generic formal concrete tagged types). Consider: generic type T is new Limited_Controlled with private; package G is ... private type Acc is access ...; type T1 is new T with record Ptr: Acc; end record; procedure Finalize(Object: in out T1); end G; package body G is ... procedure Finalize(Object: in out T1) is begin Free(Object.Ptr); Finalize(T(Object)); -- Illegal in version 4.0! end Finalize; end G; We would like to make the call to T's Finalize operation legal, because the programmer of G does not know about the actual corresponding to T -- it might have a non-abstract Finalize operation that badly needs to be called, or it might not. Making Finalize non-abstract, with a null implementation, makes it legal and safe to call T's Finalize without knowing anything more about it. Without this change, the abstraction is broken. Note that some other languages with finalization automate the calling of the parent's finalization (C++, the OOP built into the Xt level of the X Windows system). Common Lisp has a general feature for writing methods that are called *in addition* to the parent's method (instead of completely overriding it). For simplicity, we have decided not to support such functionality in Ada -- we've rationalized that "the programmer can always call the parent's operation by hand." We should make it true. The same arguments apply to Split -- it should not be abstract, but should do nothing by default. ---------------- The implementation permission in RM9X-7.6.1(20) should be deleted. This permission allows an incompletely initialized object to be finalized under certain circumstances. The intention was to ease the "PC-map" implementation approach, in which the run-time system can tell what needs to be finalized by looking at the PC when an exception is raised or an abort occurs. However, the goal is not achieved by (20). Consider: type Inner_Rec is new Limited_Controlled with record X: Integer; end record; procedure Initialize(Object: in out Inner_Rec); procedure Finalize(Object: in out Inner_Rec); function F return Inner_Rec; type Outer_Rec is new Limited_Controlled with record Y: Inner_Rec := F; end record; procedure Initialize(Object: in out Outer_Rec); procedure Finalize(Object: in out Outer_Rec); type Arr is array(Natural range <>) of Outer_Rec; A: Arr(Lower..Upper); The generated code will contain a loop from Lower to Upper to initialize A. In case the function F raises an exception, it is necessary to keep track of where in A it happened, so that the only objects finalized will be the ones that have been default-initialized (i.e. F has been called and the result assigned). The PC is not sufficient information to tell where in the array the exception occurred (unless of course the loop is unrolled, which is often infeasible). The permission in (20) does not apply in this case, because the default initialization is not complete (we're never going to call Initialize on Y, since it has a default expression). Note that we cannot extend the permission of (20) to cover this case, because some components of Y contain totally uninitialized junk -- it would be very bad to allow finalization of uninitialized junk. Since (20) causes a burden on users (it makes programs less predictable and less portable), and it does not ease the burden on implementers, we propose to remove it. Note that the PC-map implementation is still possible, but one needs to keep one piece of additional information -- the current index -- during the initialization of an array with controlled subcomponents, or, equivalently, move the compiler-generated exception handler into the initialization loop. ---------------- The name of Split should be either Split or Post_Copy. There has been much discussion of the name of the Split operation. The MRT is happy with the name Split, and would be happy with the name Post_Copy. Other names that have been suggested do not seem to us to evoke the correct meaning. This is essentially a matter of language design "style" -- there's not really much to say about it from a basic technical point of view. Therefore, we suggest that the issue be resolved at the March WG9 meeting in Switzerland.