How does 'Image for any type work? Is it generated by the compiler only when used with a specific type? What’s the runtime/space cost of using it?
You have to make a Put_Image function according to the spec here and then set the Put_Image attribute something like
for My_Type'Put_Image use My_Put_Image;
or specify it when you declare your type with an aspect:
type My_Type is ....stuff
with Put_Image => My_Put_Image;
For your implementation of the Put_Image function you can call the various Put operations (Put, Wide_Put, Wide_Wide_Put, Put_UTF_8, etc. see here.
The runtime / space cost is pretty compiler dependent and also probably dependent on your implementation of Put_Image.
If I don’t write Put_Image, I get for records a default implementation, at least with GNAT.
Yep, the compiler provides a default implementation. Speed/space is compiler dependent though, you’d need to benchmark them to see if they fit your timing requirements.
I have the same doubt and have looked for an answer:
Regarding GNAT, they don’t give any detail in their reference manual.
So let’s check:
pragma Ada_2022;
with Ada.Text_IO;
-- Type your code here, or load an example.
procedure Example is
type Example_Type is record
Int : Integer;
Char : Character;
end record;
type Test is (One, Two);
Var : Example_Type := (88, 'A');
pragma Discard_Names (Test);
--pragma Discard_Names (Example_Type);
begin
Ada.Text_IO.Put_Line (Var'Image);
Ada.Text_IO.Put_Line (One'Image);
end Example;
As you can see in Godbolt, in this program, there are constants generated for “INT =>” and “CHAR =>” in the assembler output.
But if you comment out the line Ada.Text_IO.Put_Line (Var'Image);
those constants are not generated.
I haven’t tested when the call is in a different compilation unit. If they are generated, they could be removed with --gc-sections
.
I was surprised to discover that the pragma Discard_Names only applies to enumerations, exceptions and tagged types. It hasn’t been updated for any other type. I guess there’s a reason, but it isn’t obvious.
Thank’s, that was very helpful. I forgot about Godbolt and inspected ARM assembly, which looks even worse (per instruction count).
My question was headed towards logging in debug mode, using 'Image to log entire records. It seems expensive to do in a library, but ok for an application I guess.