Version 1.2 of ai05s/ai05-0032-1.txt
!standard 6.5(5.2/2) 07-05-18 AI05-0032-1/01
!class Amendment 06-11-19
!status work item 06-11-19
!status received 06-11-19
!priority Medium
!difficulty medium
!subject Extended return statements for class-wide functions
!summary
(See proposal.)
!problem
!proposal
Imagine a device driver that registers a constructor function when it is loaded.
The constructor function returns Device'Class. Device is a limited type.
Consider how you would use an extended return to write the SCSI device
constructor:
return Obj : <specific type> do -- Not legal
This is not legal because we require the type here to be the same as that of the
function [defined in 6.5(5.2/2)]. Instead, you have to write:
return Obj : Device'Class := Func do
where Func is a dispatching call.
It seems that the first case really should be legal. An alternative view
suggests that the example is inappropriate; a constructor should be a
dispatching function, not something returning a classwide type. You could
write a factory this way, but the actual constructs should probably still be
dispatching routines. However, arguments from usage patterns are difficult to
decide. Note that this is somewhat similar to the unconstrained case, where we
allow giving constraints. For example:
function F return String is
begin
return Obj : String(1..10) do ...
!wording
Modify RM 6.5(5.2/2) as follows:
If the result subtype of the function is defined by a subtype_mark, the
return_subtype_indication shall be a subtype_indication. The type of the
subtype_indication shall be {covered by} the result type of the function. If
the result subtype of the function is constrained, then the subtype defined
by the subtype_indication shall also be constrained and shall statically
match this result subtype. If the result subtype of the function is
unconstrained, then the subtype defined by the subtype_indication shall be a
definite subtype, or there shall be an expression.
Add to the end of RM 6.5(5.8/2):
... {If the result type is class-wide, a view conversion of the return
object to the function result subtype is evaluated Redundant:[, which might
raise Constraint_Error].}
Modify RM 6.5(8/2) as follows:
If the result type of a function is a specific tagged type, the tag of the
return object is that of the result type. If the result type is class-wide,
the tag of the return object is that of {the type of the subtype_indication
if it is specific, or otherwise that of} the value of the expression. A
check is made that the accessibility level of the type identified by the tag
of the result is not deeper than that of the master that elaborated the
function body. If this check fails, Program_Error is raised.
Modify RM 6.5(23/2) as follows:
In the case of a function, the function_call denotes a constant view of the
return object. {If the result type is class-wide, this view is that created
by the view conversion of the return object to the function result subtype
(see above).}
!discussion
The example in the "problem" section above illustrates how the existing rule can
be annoying. Arguing from consistency with the existing ability to specify a
more constrained subtype in the return_subtype_indication, it seems reasonable
to allow an object of any type that would satisfy the "expected type" for the
expression in a simple_return_statement. The expected type for that expression
is the function result type. That means that if the function result type is
class-wide, then the return expression in a simple_return_statement could be of
any type covered by the class-wide type. It seems reasonable therefore to allow
the declaration of an object of any such type as the return object in an
extended_return_statement.
Note that the main wording changes are quite simple, namely adding "covered by"
to paragraph 5.2/2, and specifying that the tag comes from the subtype_
indication if it is specifc.
The changes in 5.8/2 and 23/2 are actually patching a hole that already existed,
since one could have a result subtype of "S1'Class" but specify a nominal
subtype for the return object of "S2'Class" where S1 and S2 are both subtypes of
the same type, and nowhere were we checking that the return object satisfied the
constraints of S1.
Actually, there is a bigger problem here, because it appears that in 4.6 (Type
Conversions) we don't ever do the discriminant check you would expect if you
convert S2'Class to S1'Class. The relevant sentence would be the first sentence
of RM 4.6(51/2):
After conversion of the value to the target type, if the target subtype is
constrained, a check is performed that the value satisfies this
constraint...
Unfortunately, all subtypes of a class-wide type are considered unconstrained,
because they have unknown discriminants. Furthermore, I'm not sure we ever
specify what it means to "satisfy" the constraint associated with S1'Class,
though it probably wouldn't be too hard if we first do a view conversion to
the type of S1, and then check the discriminants of that view against the
constraints of S1.
So the changes suggested above for 6.5(5.8,23) are sort of irrelevant if we
don't also add something to 4.6(51). That should probably be a separate AI.
-- Every device kind needs a constructor that creates a device control
-- block for that kind of device. This constructor is registered
-- in a table indexed by the device kind ID.
type Device_Constructor is access function (P : Param) return Device'Class;
procedure Register_Device_Constructor(Kind : Device_Kind_ID;
Constructor : Device_Constructor);
....
-- Here we define such a constructor, and then register it
-- Note that it is natural to make the return object of the
-- specific device type, rather than the class-wide type
-- used for the function result subtype.
function Make_My_Device(P : Param) return Device'Class is
begin
return Result : My_Device do
Init_My_Device(Result);
end return;
end Make_Device;
begin
Register_Device_Constructor(My_Device_Kind, Make_My_Device'access);
!ACATS test
Create an ACATS test to check that the above changes work.
!appendix
From: Tucker Taft
Sent: Friday, May 18, 2007 8:37 AM
Here is the AI [This is version /01 of the AI - ED]
on allowing the type of the return object
in an extended_return_statement to be a specific type when
the result type is class-wide. While writing this, I bumped
into what seems to be a longstanding hole in 4.6 (Type
Conversions). Given two subtypes of T'Class, S1'Class
and S2'Class, we don't ever seem to check that when converting
from S2'Class to S1'Class, that the operand satisfies
the constraints of S1. See the AI discussion section for
more on this. A related hole seems to exist in 6.5
(Return Statements), where if the result subtype is
S1'Class, we allow the return object to be declared of
subtype S2'Class, and again never check against S1.
I tried to fix this latter hole, but ended up just
presuming that 4.6 did the right thing, which it doesn't.
So another AI is probably needed to address the 4.6 hole.
Ignoring this particular existing hole, the wording changes
were quite small.
****************************************************************
From: Randy Brukardt
Sent: Friday, May 18, 2007 11:17 PM
I don't understand your hole. I don't think there is any hole in 6.5,
at least before your proposal. 6.5(5.2/2) requires static matching
of the return object subtype if the result subtype is constrained;
so if the result subtype S1'Class has a constraint, an object subtype
of S2'Class is illegal unless it has the same constraints. If the
result subtype doesn't have a constraint, there is nothing to check.
Humm, 4.6(51/2) says that after the conversion, there is a check that
the value satisfies any constraint of the target subtype if it is
constrained. What more do you need?
(If, for some bizarre reason, S1'Class is not considered constrained,
then it has no real constraints, because pretty much all of the rules
of the language are written "if constrained, then blah blah". It would
effectively act like was unconstrained. While I'd prefer this
interpretation, I don't think it was what was intended - I remember
*losing* that argument during Ada 95. And having constraints on
unconstrained subtypes seems like the first step on the road to madness...)
****************************************************************
Questions? Ask the ACAA Technical Agent