Skip to content

Commit 4e8e48b

Browse files
committed
Add first draft of RFC for improved generic instantiations
1 parent 244dce1 commit 4e8e48b

File tree

1 file changed

+272
-0
lines changed

1 file changed

+272
-0
lines changed
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
Improvements to generic instantiations
2+
======================================
3+
4+
Summary
5+
-------
6+
7+
This RFC proposes to introduce a series of enhancements to Ada generics,
8+
specifically in terms of how those are instantiated, which purpose is to make
9+
the design of high level APIs based on generics much easier than before.
10+
11+
Motivation
12+
----------
13+
14+
The generic programming system of Ada is pretty powerful, and is essential to
15+
Ada programming.
16+
17+
However, in light of other modern programming languages, it's pretty obvious
18+
that certain features are missing from it to make it truly usable in the modern
19+
programming world.
20+
21+
The general aim is to simplify the use of generics in user code, so that there
22+
is no friction when using generic subprograms and types. While there are
23+
improvements to generics from the formal point of view that could (and should)
24+
be considered for Ada, this is not the topic of that meta RFC. A few key design
25+
goals are:
26+
27+
1. The main purpose of those enhancements is a way to express implicit
28+
instantiation of generics.
29+
30+
2. Another key design goal is for users to be able to refer to a "unique"
31+
instance of a generic, by it's name. For example there will be a unique
32+
instance of `Ada.Containers.Vectors (Positive, Positive)`, and all people
33+
refering to it will refer to the same instance, which solves a long standing
34+
problem in generics, which is the ability to structurally reference unique
35+
entities.
36+
37+
This is akin to structural typing for types declared inside of generics, and
38+
is a key feature that is currently missing from Ada generics, to provide
39+
interoperability between separately evolving pieces of code. (TODO: Fill
40+
example)
41+
42+
3. We also want to simplify the way generic types (so, in other words, types
43+
which are the main interest of a generic package, like for example
44+
`Ada.Containers.Vectors.Vector`) are referred to by users, to syntactically
45+
acknowledge that they're the main entity of the package.
46+
47+
Given the following supporting generic,
48+
49+
```ada
50+
-- Supporting code
51+
generic
52+
type Index_Type is (<>);
53+
type El_Type is private;
54+
type Array_Type is array (Index_Type range <>) of El_Type;
55+
56+
type Accum is private;
57+
with function Fn (Current : Accum; El : El_Type) return Accum;
58+
function Reduce (Init : Accum; Arr : Array_Type) return Accum;
59+
```
60+
61+
This would ultimately allow people to write the following example:
62+
63+
```ada
64+
function Sum (X: Float_Array) return Float is
65+
function Red is new Reduce (Positive, Float, Float_Array, Float, "+");
66+
begin
67+
return Red (0.0, X);
68+
end Sin;
69+
```
70+
71+
This way:
72+
73+
```ada
74+
function Sum (X: Float_Array) return Float is (Reduce (Fn => "+") (X))
75+
```
76+
77+
Also, regarding generic packages & types, we would like the following:
78+
79+
```ada
80+
package Float_Vectors
81+
is new Ada.Containers.Vectors (Positive, Positive);
82+
83+
F : Float_Vectors.Vector;
84+
F2 : Float_Vectors.Vector;
85+
```
86+
87+
To be expressible this way:
88+
89+
```ada
90+
generic type Vector is Ada.Containers.Vectors (Index_Type => Positive).Vector;
91+
92+
F : Vector (Positive)
93+
F2 : Vector (Positive)
94+
```
95+
96+
### Expected high level benefits
97+
98+
More generally, we expect the following benefits from implementation of those
99+
improvements:
100+
101+
* Better code sharing/reduced code size: Due to the paradigm of explicit
102+
instantiations, it often happens because programmers cannot find duplications
103+
easily/because it's hard to share instances because of the structure of the
104+
project, that you have several instantiations with the same parameters.
105+
106+
* Better modularity:
107+
* Paradigm shift in terms of expressivity:
108+
109+
Explanation
110+
-----------
111+
112+
We will now walk through the set of proposed features that will allow us
113+
to write the above, starting from the current set of Ada's generic
114+
features.
115+
116+
### First step: Inference of dependent types in generic instantiations
117+
118+
Using the feature described in [this rfc (TODO)](https://todoaddlink),
119+
we could then simplify the above code's Reduce instantiation:
120+
121+
```ada
122+
function Sum (X: Float_Array) return Float is
123+
-- Index and element types are automatically deduced
124+
function Red is new Array_Reduce (<>, <>, Float_Array, Float, "+");
125+
begin
126+
return Red (0.0, X);
127+
end Sin;
128+
```
129+
130+
Here, we're allowed to not specify generic actual parameters for parameters
131+
that can be deduced from other parameters, according to the rules described in
132+
the RFC.
133+
134+
This simplifies the instantiation of the `Array_Reduce` generic function a
135+
little, but is not a big step up from the last version. We will understand the
136+
true edge this feature gives us in the last step. Let's go to the next
137+
iteration
138+
139+
### Second step: Implicit instantiation of generics
140+
141+
This one is the big step up, that will allow us to get one step closer to the
142+
initial intent. Using implicit instantiation of generic functions [(see RFC
143+
here (TODO))](https://TODO), we would be able to write the following:
144+
145+
```ada
146+
function Sum (X: Float_Array) return Float is
147+
begin
148+
return Array_Reduce (<>, <>, Float_Array, Float, 0.0, "+") (0.0, X);
149+
end Sum;
150+
```
151+
152+
The last step we would like to get rid of is the repetitive
153+
instantiation parameters.
154+
155+
156+
> **Note**
157+
> Above we only show the syntax for functions, but packages can also be
158+
> structurally instantiatedtypes
159+
160+
### Third step: inference of generic actual parameters from function call params
161+
162+
Using inference of actual generic actuals using call actuals
163+
[(see RFC here (TODO))](https://TODO), we can express the above as:
164+
165+
```ada
166+
function Sum (X: Float_Array) return Float is
167+
begin
168+
return Array_Reduce (Fn => "+") (0.0, X);
169+
end Sum;
170+
```
171+
172+
Here, the only generic actual we have to specify is \`Fn\`, because:
173+
174+
- All array type parameters are infered from the `Self` actual
175+
parameter. `Self` allows us to deduce the type of the `Array_Type`
176+
generic formal, and from this we can deduce the `Index_Type` and
177+
`Element_Type`.
178+
179+
- The `Accum` type can be deduced either from the value of `Init`, or
180+
from the expected target type of the function call. In this case,
181+
since `0.0` is an universal real, we deduce `Accum` from the
182+
expected type of the function call, which is the return type of the
183+
`Sin` function.
184+
185+
> **Note**
186+
> In terms of how implicit instantiations work, we can wonder whether each
187+
> reference to an instantiation with the same parameters refers to **the same
188+
> instance**, or to **a different one each time**.
189+
>
190+
> Following from the high level design point number 2 in the motivation, we
191+
> clearly want each instantiation with similar structural parameters to refer to
192+
> the same instantiation.
193+
>
194+
> In terms of name resolution, it means that, given two implicit instantiation
195+
> references, they'll reference the same instantiation if their parameters are
196+
> the same.
197+
198+
> **Note**
199+
> There is a big question here in my opinion in how we refer to that feature.
200+
> Talking about implicit instantiation is maybe not the best terminology. Some
201+
> other ideas:
202+
>
203+
> * "Structural instantiations" might be better in how it coins the nature of the
204+
> feature.
205+
>
206+
> * A natural one for Ada would be "Anonymous instantiations". For me the only
207+
> problem with this name is the potential PTSD from coming from anonymous
208+
> accesses/array declarations.
209+
210+
211+
### Fourth step: Generic types
212+
213+
With the current discussed features, the `Vector` example in the motivation
214+
section can be expressed as:
215+
216+
```ada
217+
F : Ada.Containers.Vectors (Positive, Positive).Vector;
218+
F2 : Ada.Containers.Vectors (Positive, Positive).Vector;
219+
```
220+
221+
Which is pretty verbose. One could imagine that, in that case, the user can
222+
just make an explicit instantiation if they need a shorter name. The problem
223+
with that scheme is that, one of the features that we want to derive from
224+
implicit instantiations is structural typing of generics, so **conciseness is
225+
not the only reason to use generics**.
226+
227+
For that use, we propose the "generic types" feature (TODO link to RFC), that
228+
will in effect add a new kind of generic entity to Ada. However, at least for
229+
the moment, the way this will be done is still hugely relying on generic
230+
packages:
231+
232+
```ada
233+
generic type Vector is Ada.Containers.Vectors.Vector;
234+
-- This declares that uses of ``Vector`` are really uses of
235+
-- Ada.Containers.Vectors.
236+
237+
type Float_Vector is new Vector (Positive, Float);
238+
-- Declare a new instantiation explicitly
239+
240+
Inst : Float_Vector;
241+
242+
F : Vector (Positive, Positive)
243+
F2 : Vector (Positive, Positive)
244+
-- Refer to the structural instantiation
245+
```
246+
247+
248+
### Fifth step: Partial instantiation of generics
249+
250+
A feature that has often been asked in Ada is partial instantiations of
251+
generics, in fact, it has been asked on ada-spark-rfcs by an external user
252+
already, see https://github.com/AdaCore/ada-spark-rfcs/pull/41.
253+
254+
This feature has great consequences on generic's usability beyond the scope of
255+
instantiations, but in the scope of this document, which are detailed in the
256+
RFC itself, but in the context of instantiations, and of the example of
257+
`Vectors`, it would allow the following:
258+
259+
```ada
260+
generic type Vector is Ada.Containers.Vectors (Index_Type => Positive).Vector;
261+
262+
F : Vector (Positive)
263+
F2 : Vector (Positive)
264+
```
265+
266+
Prior art
267+
---------
268+
269+
Many (most) languages with generics have implicit/structural instantiations of
270+
generics. It's on the other hand hard to find languages with explicit
271+
instantiations like Ada. All mainstream languages today use implicit/structural
272+
generics (Java/C++/C#/Rust/Go/etc).

0 commit comments

Comments
 (0)