I do not understand why the following is not allowed:
type IncludesClass is record
Int: Integer;
Some: Sometype'Class
end record;
The class-wide type is at the end, so there should be no problem with the layout. It is an indefinite type, and we can instantiate it without initialization.
Record types with an unconstrained array require a discriminant, which can’t be given here.
But what’s the issue with declaring that type indefinite/limited ? The component would get the tag and the object’s size calculated when instanciating.
The issue is the compiler needs to know the size of the IncludesClass type itself at compile time before any instantiations are made. All of the derived types of Sometype’Class could have different sizes. Which one does it pick for the type itself? You are correct that it could potentially figure out the size of the objects themselves at compile time (in some cases, but not all, what if initialized by a function call?), but for a definite type Ada needs to guarantee knowing the size of the type at compile time, not just the individual variables.
Keep in mind, that Ada has to be able to allow you to make an array of definite types, so it needs to be able to allow you to make the following type: type IncludesClass_Array is array(Positive range <>) of IncludesClass, which it cannot do without knowing a global size for the type itself.
type Base is array (positive range <>) of Integer;
type ARR (A: Positive) is record
B : Base (1..A);
end record;
This won’t compile if you try to create an instance of Arr:
1. procedure Indefinites is
2. type Base is array (Positive range <>) of Integer;
3. type Arr (A : Positive) is record
4. B : Base (1 .. A);
5. end record;
6. A : Arr;
|
>>> error: unconstrained subtype not allowed (need initialization)
>>> error: provide initial value or explicit discriminant values
>>> error: or give default discriminant values for type "Arr"
7. begin
8. null;
9. end Indefinites;
You could say A : Arr (10);.
You could try
type Arr (A : Positive := 10) is record
B : Base (1 .. A);
end record;
A : Arr;
What?
This is because when you give a discriminant like this a default, the language allows you to change it … so the compiler reserves sufficient space … in this case, room for Positive’Last integers. You can work round this by using an appropriate subrange of the discriminant type.
The thing about class-wide types is that you can’t know what instances of the type may be declared elsewhere, possibly in several years time.
I think that there’s a proposed extension where you can define the maximum size a class instance is allowed to have? Sounds like a Bad Idea for any code outside a tightly-controlled environment.
Hence I mentioned a variant and not mutable type. My point was, why is this ok:
type Base is array (positive range <>) of Integer;
type ARR (A: Positive) is record
B : Base (1..A);
end record;
A: Arr := Some_constructor;
but not this:
type Base is tagged private;
type ARR is record
B: Base'Class;
end record;
A: Arr := (others => some_constructor);
Yes size can’t be predicted because new classes could be added, but it’s no different from other indefinite or unconstrained type: just require initialization, a default component value, or a tag in discriminant, just like with arrays.
type Crazy (L1, L2 : Natural) is record
S1 : String (1..L1);
S2 : String (1..L2);
end record;
Not only the size can be variable but offsets to the record members too.
Variant part is more limited. There can be only one at the end. But you can nest them! I do not remember I ever used it. It must be a big headache for compiler vendors…
P.S. Problems with proper composition is why full MI is so much welcome.
P.P.S. Proper here means that the objects remain contiguous and can be allocated on the stack.
Quit doing this — it makes it hard to follow the thread.
Yeah, off the cuff, that feature sounds like it would fry the ability to write libraries nicely.
No, your question was deleted, but I can answer it easily:
Because you cannot have a value of an unconstrained type in a record. The construct Base (1..A)is constraining the subtype, in this case to the length of A — likewise, Base'Class is unconstrained, but not null access Base'Class is constrained, as is an instance of Indefinite_Holders.Holder.
Sorry I just copied the post because I hadn’t finished writing it, before someone posted something else I was responding to… a mess. I won’t do it again.
The main difference is in how the record itself is declared: type ARR (A: Positive) is record
vs type ARR is record
The first says that size of objects of this record might be determinable at compile time or they might not be (so it’s fields can be indefinite as long as they reference the discriminant), but the second says that size of objects of that records are always determinable at compile time so it’s fields must always be definite.
Also again, you cannot make an array of the first type (unless you make a constrained subtype/derived type first) while the language expects that you can make an array of the second type.
I definitely would like a way to do the second more easily as well, so don’t take my comments as I disagree with what you are looking for.
The RFC (showing evidence of deep thought) lays out many ways in which things could go wrong while implementing what seemed at first glance to be a straightforward requirement. E.g.
If the Size'Class aspect is specified for a type T, then every specific descendant of T [redundant: (including T)]
shall have a Size that does not exceed the specified value; and
shall be undiscriminated; and
shall have no composite subcomponent whose subtype is subject to a dynamic constraint; and
shall have no interface progenitors; and
shall not have a tagged partial view other than a private extension; and
shall not have a statically deeper accessibility level than that of T.
So someone at Adacore will need to implement those checks, and think of a way of pointing the user towards the error they’ve actually made if a check fails.
Also, we have at least one new concept (“tag-constrained”; is “mutably tagged” defined?) which I can guess at but don’t find clear.