Skip to content

Commit af115f7

Browse files
author
Denis Mazzucato
committed
Revision of direct attribute definitions
1 parent 854fb29 commit af115f7

File tree

1 file changed

+148
-15
lines changed

1 file changed

+148
-15
lines changed

features/rfc-oop-attributes.rst

Lines changed: 148 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ Motivation
1111
Guide-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
1518
subprogram 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+
61194
Reference-level explanation
62195
===========================
63196

0 commit comments

Comments
 (0)