@@ -11,7 +11,10 @@ Motivation
1111Guide-level explanation
1212=======================
1313
14- Today, specifying a subprogram attribute of a type requires to declare a
14+ Direct Attribute definitions
15+ ----------------------------
16+
17+ Currently, specifying a subprogram attribute of a type requires to declare a
1518subprogram and then to use an aspect or an attribute to link it to a type, e.g.
1619
1720.. code-block :: ada
@@ -20,44 +23,174 @@ subprogram and then to use an aspect or an attribute to link it to a type, e.g.
2023
2124 for T'Write use My_Write;
2225
23- procedure My_Write(
24- Stream : not null access Ada.Streams.Root_Stream_Type'Class;
26+ procedure My_Write
27+ (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
28+ Item : in T);
29+
30+ Or directly into the type declaration via an aspect specification
31+
32+ .. code-block :: ada
33+
34+ type T is null record with Write => My_Write;
35+
36+ procedure My_Write
37+ (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
2538 Item : in T);
2639
27- This proposal allows to define directly the procedure as being an attribute of
28- the type:
40+ This proposal introduces * direct attribute definitions * that allows to define
41+ directly the procedure as being an attribute of the type:
2942
3043.. code-block :: ada
3144
3245 type T is null record;
3346
34- procedure T'Write(
35- Stream : not null access Ada.Streams.Root_Stream_Type'Class;
47+ procedure T'Write
48+ ( Stream : not null access Ada.Streams.Root_Stream_Type'Class;
3649 Item : in T);
3750
38- In addition, this can be used as a scoped attribute, possibly with re-ordering
39- of parameters to ensure that the first parameter is conceptually the one
40- "owning" the primitive, e.g.:
51+ In addition, this can be used within scoped records, e.g.:
4152
4253.. code-block :: ada
4354
4455 type T is tagged record
4556
46- procedure T'Write(
47- Stream : not null access Ada.Streams.Root_Stream_Type'Class;
57+ procedure T'Write
58+ ( Stream : not null access Ada.Streams.Root_Stream_Type'Class;
4859 Item : in T);
4960
5061 end T;
5162
52- This provide a seamless solution in particular to scope a destructor:
53-
63+ This provide a seamless solution in particular to scope oop primitives:
5464
5565.. code-block :: ada
5666
57- type T is tagged record
67+ type T is class record
68+ procedure T'Constructor (Self : in out T);
5869 procedure T'Destructor (Self : in out T);
5970 end record;
6071
72+ Unfortunately, the direct attribute definitions inside a scoped record clashes
73+ with the class type rules where each subprogram is required to be primitive
74+ following the rules of First_Controlling_Parameter (e.g., see `T'Write ` above
75+ where `Item ` is the second formal). The rule's motivation comes from the idea
76+ that class' primitives are called with the prefix notation.
77+
78+ To solve this conflict, we could either:
79+
80+ 1. Re-order parameters to ensure that the first parameter is conceptually the
81+ one "owning" the primitive. We do so by moving to front the first occurrence
82+ of a formal with the same type of the record scope it is declared in. The
83+ example above would then extend to:
84+
85+ .. code-block :: ada
86+
87+ type T is tagged record
88+
89+ procedure Internal_T_Write (
90+ Item : in T;
91+ Stream : not null access Ada.Streams.Root_Stream_Type'Class);
92+
93+ end T;
94+
95+ procedure Reordered_Internal_T_Write (
96+ Stream : not null access Ada.Streams.Root_Stream_Type'Class;
97+ Item : in T) is
98+ begin
99+ Item.Internal_T_Write (Stream);
100+ end Reordered_Internal_T_Write;
101+
102+ for T'Write use Reordered_Internal_T_Write;
103+
104+ 2. Otherwise, given that attribute calls (such as `T'Write (S, I) ` in a
105+ statement) are somehow different from subprogram calls and will not employ a
106+ prefixed notation even when defined in the scoped record, then it could make
107+ sense to remove the burden of the First_Controlling_Parameter for such
108+ entities.
109+
110+ In short, the first approach is less clean and a bit cumbersome when no formal
111+ is of the enclosing type (a new unused one could be introduced). The second
112+ approach threats differently attribute definitions from the others, exceptions
113+ may create complexity in the implementation side.
114+
115+ Direct Aspect definitions
116+ -------------------------
117+
118+ So far only a small set of attributes denote callable subprograms: stream and
119+ I/O operations. However, a similar shorthand definition envisioned in this rfc
120+ could be useful as is for aspects. For instance, we could define a container
121+ as:
122+
123+ .. code-block :: ada
124+
125+ type Indexable_Container is tagged record
126+
127+ function Indexable_Container'Constant_Indexing
128+ (Container : aliased Indexable_Container;
129+ Position : Offset) return Constant_Reference_Type;
130+
131+ function Indexable_Container'Constant_Indexing -- overloading
132+ (Container : aliased Indexable_Container;
133+ Position : Custom_Offset) return Constant_Reference_Type;
134+
135+ function Indexable_Container'Variable_Indexing
136+ (Container : aliased in out Indexable_Container;
137+ Position : Offset) return Reference_Type;
138+
139+ end record;
140+
141+ That expands to the aspects named `Constant_Indexing ` and `Variable_Indexing `
142+ respectively.
143+
144+ Apart from the benefit of grouping locally all operations together, and remove
145+ the need of temporary subprograms, the shorthand for aspects removes all
146+ together the class of errors from name resolution rules. For example, we don't
147+ need to worry of `Indexable_Container'Constant_Indexing ` homonyms since that
148+ name doesn't clash with anything else other than its second overloading, but a
149+ mismatch in the profile would be easy to spot in that case.
150+
151+ This inline notation could be shortened further, potential candidates are:
152+
153+ - Usage of `@'Attribute ` since `@ ` can be resolved to the enclosing record name
154+ similarly to the shorthand for the left hand side of assignments. The big
155+ advantage is when the record name is a bit cumbersome. We could rewrite the
156+ container above as:
157+
158+ .. code-block :: ada
159+
160+ type Indexable_Container is tagged record
161+
162+ function @'Constant_Indexing
163+ (Container : aliased @;
164+ Position : Offset) return Constant_Reference_Type;
165+
166+ function @'Constant_Indexing
167+ (Container : aliased @;
168+ Position : Custom_Offset) return Constant_Reference_Type;
169+
170+ function @'Variable_Indexing
171+ (Container : aliased in out @;
172+ Position : Offset) return Reference_Type;
173+
174+ end record;
175+
176+ More in general, the `@` symbol could be used anywhere in the scoped record
177+ resolving to the record name. Another example with the `Aggregate` aspect
178+ would look like the following:
179+
180+ .. code-block:: ada
181+
182+ type Container_Type (Cap : Positive) is tagged private
183+
184+ function @'Aggregate'Empty (Cap : Positive) return @;
185+
186+ procedure @'Aggregate'Add_Unnamed (Self : in out @; New_Item : T);
187+
188+ end record;
189+
190+ - Or, the usage of just `'Attribute`` without the prefix name when inside
191+ scoped records. This second notation would only avoid writing the record name
192+ once, thus less preferred than the option above.
193+
61194Reference-level explanation
62195===========================
63196
0 commit comments