Array of discriminated tasks

Sorry I got confused in fact it’s not even the idea I had in mind. You’re right of course.
“On the stack” doesn’t mean “at the same address” like a record component.
So there is no need for systematic heap allocation: It should be treated just an aliased object declared in the same scope as the enclosing object and leaving just a pointer as a field in the object with the access discriminant. Seems so simple I don’t get why it hasn’t been implemented yet. Then no dynamic size issue.
edit: removed first message by mistake.

I see, the variant parts would make sense, though still a bit confusing to me why a default value is accepted by the compiler when calculating the storage requirements.

For example, given this:

type Integer_Array is array(Positive range <>) of Integer;
type Thing(Double_Size : Boolean := False) is record
  case Double_Size is
   when False => Small : Integer_Array (1 .. 10);
   when True  => Large : Integer_Array (1 .. 20);
  end case;
end record;
type Thing_Arr is array (Integer range 1 .. 2) of Thing;

and this:

TA : Thing_Arr := ((Double_Size => False, others => <>), (Double_Size => True, others => <>));

then during compilation the compiler would presumably allocate two Thing’s space for the default value of False (for example 1 byte + (4 bytes x 10) plus space for some other auxiliary structures perhaps) and then during elaboration two components with different sizes would probably be created on the stack (I believe?) for TA. Perhaps, the elaboration and compilation phases don’t work under assumptions for each phase?

Though given this:

Equal_Size : Boolean := TA (1)'Size = TA (2)'Size;

and this:

Put_Line (TA (1)'Size'Image);
Put_Line (TA (2)'Size'Image);
Put_Line (Equal_Size'Image);

I’m getting:

 672 --   spaces padded due to raw 'Image
 672
TRUE

on my target machine (running this on a recent version of Ubuntu and using gnat_native=14.2.1) maybe because 'Size is the static size for the default value of False?

I’m not sure what the reasoning for the specific method of using the default value was chosen. There might be an old AI with discussion on it at the ARG website, but I’m not sure. But either way they needed a way to have a fixed size for all variants so you could make an array of Thing objects. Otherwise if you did

type Integer_Array is array(Positive range <>) of Integer;
type Thing(Double_Size : Boolean) is record
  case Double_Size is
   when False => Small : Integer_Array (1 .. 10);
   when True  => Large : Integer_Array (1 .. 20);
  end case;
end record;

then without the default then the following couldn’t compile

type Thing_Arr is array (Integer range 1 .. 2) of Thing;

Since the compiler has no clue how to determine a size at compile time, and Sizes for types must be static.

Keep in mind that Elaboration is a run time construct and type sizes must be known at compile time. In the case of the default discriminated record, GNAT doesn’t pick the size of the default, it picks the size of the largest variant (in my example that would actually be the True variant) and uses that for the type’s size. Other compilers can use other methods as the method isn’t specified by the language, only that the size must be known at compile time (if I remember correctly the Janus Ada compiler actually uses a different method involving heap allocation).

Yep the 'Size is static for a type, though in this case they are using the size of the largest variant which is True (array of 20 elements) rather than False (array of 10 elements).

on my target machine (running this on a recent version of Ubuntu and using gnat_native=14.2.1) maybe because 'Size is the static size for the default value of False?

On thing of note, given:

type Integer_Array is array(Positive range <>) of Integer;
type Thing(Double_Size : Boolean := False) is record
  case Double_Size is
   when False => Small : Integer_Array (1 .. 10);
   when True  => Large : Integer_Array (1 .. 20);
  end case;
end record;

and then

v1 : Thing;
v2 : Thing(False);
v3 : Thing(True);

You’ll probably see a different size for v2 versus v1 and v3

Remember that in Ada, discriminants are more than just “fields”, they are part of the type. So Thing(False) and Thing(True) are technically different subtypes in Ada

Yep, as you said, gnat seems to be picking as default the largest of the two (i.e. True in this case) so running:

Put_Line (v1'Size'Image);
Put_Line (v2'Size'Image);
Put_Line (v3'Size'Image);

yields:

 672
 352
 672

(so it looks like Thing and Thing(True) are probably designated by the same type in this compiler).

Thanks very much for sharing those details.

No problem, but keep in mind that the language does distinguish between Thing and Thing(True) at a type level, so they are not completely the same.

1 Like