Ada Reference Manual (Ada 2022) — Legal Information

# 4.2.1 User-Defined Literals

1/5
Using one or more of the aspects defined below, a type may be specified to allow the use of one or more kinds of literals as values of the type.

#### Static Semantics

2/5
The following type-related operational aspects (collectively known as user-defined literal aspects) may be specified for a type T:
3/5
Integer_Literal
This aspect is specified by a function_name that statically denotes a function with a result type of T and one in parameter that is of type String and is not explicitly aliased.
4/5
Real_Literal
This aspect is specified by a function_name that statically denotes a function with a result type of T and one in parameter that is of type String and is not explicitly aliased, and optionally a second function (overloading the first) with a result type of T and two in parameters of type String that are not explicitly aliased.
5/5
String_Literal
This aspect is specified by a function_name that statically denotes a function with a result type of T and one in parameter that is of type Wide_Wide_String and is not explicitly aliased.
6/5
User-defined literal aspects are nonoverridable (see 13.1.1).
7/5
When a numeric literal is interpreted as a value of a non-numeric type T or a string_literal is interpreted as a value of a type T that is not a string type (see 4.2), it is equivalent to a call to the subprogram denoted by the corresponding aspect of T: the Integer_Literal aspect for an integer literal, the Real_Literal aspect for a real literal, and the String_Literal aspect for a string_literal. The actual parameter of this notional call is a string_literal representing a sequence of characters that is the same as the sequence of characters in the original numeric literal, or the sequence represented by the original string literal.
8/5
Such a literal is said to be a user-defined literal.
9/5
When a named number that denotes a value of type universal_integer is interpreted as a value of a non-numeric type T, it is equivalent to a call to the function denoted by the Integer_Literal aspect of T. The actual parameter of this notional call is a String having a textual representation of a decimal integer literal optionally preceded by a minus sign, representing the same value as the named number.
10/5
When a named number that denotes a value of type universal_real is interpreted as a value of a non-numeric type T, it is equivalent to a call to the two-parameter function denoted by the Real_Literal aspect of T, if any. The actual parameters of this notional call are each a String with the textual representation of a decimal integer literal, with the first optionally preceded by a minus sign, where the first String represents the same value as the numerator, and the second the same value as the denominator, of the named number when represented as a rational number in lowest terms, with a positive denominator.

#### Legality Rules

11/5
The Integer_Literal or Real_Literal aspect shall not be specified for a type T if the full view of T is a numeric type. The String_Literal aspect shall not be specified for a type T if the full view of T is a string type.
12/5
For a nonabstract type, the function directly specified for a user-defined literal aspect shall not be abstract.
13/5
For a tagged type with a partial view, a user-defined literal aspect shall not be directly specified on the full type.
14/5
If a nonabstract tagged type inherits any user-defined literal aspect, then each inherited aspect shall be directly specified as a nonabstract function for the type unless the inherited aspect denotes a nonabstract function, or functions, and the type is a null extension.
15/5
If a named number that denotes a value of type universal_integer is interpreted as a value of a non-numeric type T, T shall have an Integer_Literal aspect. If a named number that denotes a value of type universal_real is interpreted as a value of a non-numeric type T, T shall have a Real_Literal aspect, and the aspect shall denote a function that has two in parameters, both of type String, with result of type T.
16/5
In addition to the places where Legality Rules normally apply (see 12.3), these rules also apply in the private part of an instance of a generic unit.

#### Bounded (Run-Time) Errors

17/5
It is a bounded error if the evaluation of a literal or named number that has an expected type with a specified user-defined literal aspect propagates an exception. Either Program_Error or the exception propagated by the evaluation is raised at the point of use of the value of the literal or named number. If it is recognized prior to run time that evaluation of such a literal or named number will inevitably (if executed) result in such a bounded error, then this may be reported as an error prior to run time.

#### Examples

18/5
Examples of the specification and use of user-defined literals:
19/5
subtype Roman_Character is Wide_Wide_Character
with Static_Predicate =>
Roman_Character in 'I' | 'V' | 'X' | 'L' | 'C' | 'D' | 'M';
20/5
Max_Roman_Number : constant := 3_999; -- MMMCMXCIX
21/5
type Roman_Number is range 1 .. Max_Roman_Number
with String_Literal => To_Roman_Number;
22/5
function To_Roman_Number (S : Wide_Wide_String) return Roman_Number
with Pre => S'Length > 0 and then
(for all Char of S => Char in Roman_Character);
23/5
function To_Roman_Number (S : Wide_Wide_String) return Roman_Number is
(declare
R : constant array (Integer range <>) of Roman_Number :=
(for D in S'Range => Roman_Digit'Enum_Rep
(Roman_Digit'Wide_Wide_Value (''' & S(D) & ''')));
-- See 3.5.2 and 13.4
begin
[for I in R'Range =>
(if I < R'Last and then R(I) < R(I + 1) then -1 else 1) * R(I)]
'Reduce("+", 0)
);
24/5
X : Roman_Number := "III" * "IV" * "XII"; -- 144 (that is, CXLIV)

Ada 2005 and 2012 Editions sponsored in part by Ada-Europe