Skip to content

Latest commit

 

History

History
138 lines (89 loc) · 4.87 KB

image-redefine.md

File metadata and controls

138 lines (89 loc) · 4.87 KB

Ada 2020: Redefining the 'Image attribute

This post is a part of the Ada 2020 series.

You can launch this notebook with Jupyter Ada Kernel by clicking this button:

Binder

Ada 2020 activation

Firstly, let's activate Ada 2020 support in the compiler. Usually we do this by -gnat2020 option in compiler command line or in the project file (preferred). But in this notebook we will do this by the pragma Ada_2020. Also we will need the Text_IO package.

pragma Ada_2020;

with Ada.Text_IO;

In Ada 2020 you can redefine 'Image attribute for your type. And GNAT Community Edition 2020 does it in its-own (rather ugly from my point of view) way. It differs from ARM 2020 Draft.

A bit of history

Initially, ARG used Ada.Streams.Root_Stream_Type'Class to write a string image there. I didn't like this approach, because it's too low-level, error prone and nonportable, so I wrote a proposal. I proposed to add a new abstraction Output_Text_Stream, where you can write Wide_Wide_String to. No encodings games, not CR/LF handling, no ridiculous UTF8_Strings. I have no explanation why the proposal isn't good enough nor argument why it should be done in a different way. Instead the Standard was changed by adding Root_Buffer_Type, where you can Put a Wide_Wide_String and Get a String with no idea how it will be converted.

A working example

So, how GNAT CE 2020 does this? It does in a complete different way, I would say.

Firstly, you need some package:

with Ada.Strings.Text_Output.Utils;

Then, for your type you will define a new aspect Put_Image:

package Source_Locations is
   type Source_Location is record
      Line   : Positive;
      Column : Positive;
   end record
     with Put_Image => My_Put_Image;

   procedure My_Put_Image
     (Sink  : in out Ada.Strings.Text_Output.Sink'Class;
      Value : Source_Location);
end Source_Locations;

package body Source_Locations is

   procedure My_Put_Image
     (Sink  : in out Ada.Strings.Text_Output.Sink'Class;
      Value : Source_Location)
   is
      Line   : constant String := Value.Line'Image;
      Column : constant String := Value.Column'Image;
      Result : constant String :=
        Line (2 .. Line'Last) & ':' & Column (2 .. Column'Last);
   begin
       Ada.Strings.Text_Output.Utils.Put_UTF_8 (Sink, Result);
   end My_Put_Image;

end Source_Locations;

Let's define some object

Line_10 : Source_Locations.Source_Location := (Line => 10, Column => 1);

Now print its 'Image

Ada.Text_IO.Put_Line ("Text position: " & Line_10'Image);
Text position: 10:1

Looks like it works. But, will it work in non-UTF-8 environment? No body knows, because it's implementation defined, I guess.

What's the Sink?

Let's see how Ada.Strings.Text_Output.Sink is defined.

   type Sink (<>) is abstract tagged limited private;
   type Sink_Access is access all Sink'Class with Storage_Size => 0;
   --  Sink is a character sink; you can send characters to a Sink.
   --  UTF-8 encoding is used.

   procedure Full_Method (S : in out Sink) is abstract;
   procedure Flush_Method (S : in out Sink) is abstract;

So,

  • How to write strings to the Sink?
  • Why should I use UTF-8?
  • Will it work in non-utf-8 environment?
  • How to write a muliline image in a portable way?
  • Will it do a correct Unicode handling for me?
  • Can I use my-own Sink to stream value image into a DB or XML, for instance?
  • Can we convince the ARG to do this better or just open the discussion to the community?

I don't know. Do I like this? Not at all.

Do you?

References:


Do you like this? Support us on patreon!

Live discussions: Telegram, Matrix.