User-Defined Literals
Note
User-defined literals are supported by
GNAT Community Edition 2020
GCC 11
In Ada 2022, you can define string, integer, or real literals for your types. The compiler will convert such literals to your type at run time using a function you provide. To do so, specify one or more new aspects:
Integer_Literal
Real_Literal
String_Literal
For our example, let's define all three for a simple type and see how
they work. For simplicity, we use a Wide_Wide_String
component
for the internal representation:
pragma Ada_2022; with Ada.Wide_Wide_Text_IO; with Ada.Characters.Conversions; procedure Main is type My_Type (Length : Natural) is record Value : Wide_Wide_String (1 .. Length); end record with String_Literal => From_String, Real_Literal => From_Real, Integer_Literal => From_Integer; function From_String (Value : Wide_Wide_String) return My_Type is ((Length => Value'Length, Value => Value)); function From_Real (Value : String) return My_Type is ((Length => Value'Length, Value => Ada.Characters.Conversions.To_Wide_Wide_String (Value))); function From_Integer (Value : String) return My_Type renames From_Real; procedure Print (Self : My_Type) is begin Ada.Wide_Wide_Text_IO.Put_Line (Self.Value); end Print; begin Print ("Test ""string"""); Print (123); Print (16#DEAD_BEEF#); Print (2.99_792_458e+8); end Main;
As you see, real and integer literals are converted to strings while
preserving the formatting in the source code, while string literals
are decoded: From_String
is passed the specified string value.
In all cases, the compiler translates these literals into function
calls.
Turn Ada into JavaScript
Do you know that '5'+3 in JavaScript is 53?
> '5'+3
'53'
Now we can get the same result in Ada! But before we do, we need to
define a custom +
operator:
pragma Ada_2022; with Ada.Wide_Wide_Text_IO; with Ada.Characters.Conversions; procedure Main is type My_Type (Length : Natural) is record Value : Wide_Wide_String (1 .. Length); end record with String_Literal => From_String, Real_Literal => From_Real, Integer_Literal => From_Integer; function "+" (Left, Right : My_Type) return My_Type is (Left.Length + Right.Length, Left.Value & Right.Value); function From_String (Value : Wide_Wide_String) return My_Type is ((Length => Value'Length, Value => Value)); function From_Real (Value : String) return My_Type is ((Length => Value'Length, Value => Ada.Characters.Conversions.To_Wide_Wide_String (Value))); function From_Integer (Value : String) return My_Type renames From_Real; procedure Print (Self : My_Type) is begin Ada.Wide_Wide_Text_IO.Put_Line (Self.Value); end Print; begin Print ("5" + 3); end Main;
Jokes aside, this feature is very useful. For example it allows a "native-looking API" for big integers.